[libnma/lr/nma-ws: 23/26] nma-ws: add



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

    nma-ws: add
    
    This is a library based on src/wireless-security that aims to replace
    it, providing a public API in libnma.
    
    The wireless-security code is used by the wifi-dialog provided by libnma,
    nm-applet, nm-connection-editor and gnome-control-center, that should all be
    ported to this common library.

 Makefile.am                        |  63 ++++-
 NEWS                               |   7 +
 meson.build                        |   1 +
 po/POTFILES.in                     |  27 ++
 src/libnma.ver                     |  22 ++
 src/meson.build                    |  10 +-
 src/nma-version.h.in               |   6 +
 src/nma-ws/meson.build             |  45 ++++
 src/nma-ws/nma-eap-fast.c          | 438 ++++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-fast.h          |  20 ++
 src/nma-ws/nma-eap-fast.ui         | 166 ++++++++++++
 src/nma-ws/nma-eap-leap.c          | 257 ++++++++++++++++++
 src/nma-ws/nma-eap-leap.h          |  19 ++
 src/nma-ws/nma-eap-leap.ui         |  82 ++++++
 src/nma-ws/nma-eap-peap.c          | 486 ++++++++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-peap.h          |  20 ++
 src/nma-ws/nma-eap-peap.ui         | 195 ++++++++++++++
 src/nma-ws/nma-eap-simple.c        | 485 ++++++++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-simple.h        |  49 ++++
 src/nma-ws/nma-eap-simple.ui       | 141 ++++++++++
 src/nma-ws/nma-eap-tls.c           | 497 ++++++++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-tls.h           |  20 ++
 src/nma-ws/nma-eap-tls.ui          |  89 +++++++
 src/nma-ws/nma-eap-ttls.c          | 521 ++++++++++++++++++++++++++++++++++++
 src/nma-ws/nma-eap-ttls.h          |  20 ++
 src/nma-ws/nma-eap-ttls.ui         | 148 +++++++++++
 src/nma-ws/nma-eap.c               | 424 +++++++++++++++++++++++++++++
 src/nma-ws/nma-eap.h               | 106 ++++++++
 src/nma-ws/nma-ws-802-1x-private.h |  37 +++
 src/nma-ws/nma-ws-802-1x.c         | 528 +++++++++++++++++++++++++++++++++++++
 src/nma-ws/nma-ws-802-1x.h         |  33 +++
 src/nma-ws/nma-ws-802-1x.ui        |  72 +++++
 src/nma-ws/nma-ws-dynamic-wep.c    |  68 +++++
 src/nma-ws/nma-ws-dynamic-wep.h    |  34 +++
 src/nma-ws/nma-ws-helpers.c        |  31 +++
 src/nma-ws/nma-ws-helpers.h        |  18 ++
 src/nma-ws/nma-ws-leap.c           | 293 ++++++++++++++++++++
 src/nma-ws/nma-ws-leap.h           |  32 +++
 src/nma-ws/nma-ws-leap.ui          |  86 ++++++
 src/nma-ws/nma-ws-private.h        |  27 ++
 src/nma-ws/nma-ws-sae.c            | 285 ++++++++++++++++++++
 src/nma-ws/nma-ws-sae.h            |  30 +++
 src/nma-ws/nma-ws-sae.ui           |  84 ++++++
 src/nma-ws/nma-ws-wep-key.c        | 457 ++++++++++++++++++++++++++++++++
 src/nma-ws/nma-ws-wep-key.h        |  35 +++
 src/nma-ws/nma-ws-wep-key.ui       | 161 +++++++++++
 src/nma-ws/nma-ws-wpa-eap.c        |  70 +++++
 src/nma-ws/nma-ws-wpa-eap.h        |  35 +++
 src/nma-ws/nma-ws-wpa-psk.c        | 303 +++++++++++++++++++++
 src/nma-ws/nma-ws-wpa-psk.h        |  32 +++
 src/nma-ws/nma-ws-wpa-psk.ui       |  83 ++++++
 src/nma-ws/nma-ws.c                | 141 ++++++++++
 src/nma-ws/nma-ws.h                |  56 ++++
 src/nma.gresource.xml              |  11 +
 src/wireless-security/ws-leap.ui   |   2 +-
 55 files changed, 7397 insertions(+), 11 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index fe109f2d..bb54e55b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -253,12 +253,12 @@ src/nma-resources.c: src/nma.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --s
        $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< --target=$@ --sourcedir=$(srcdir)/src --generate-source 
--internal
 
 src/libnma-gtk4/nma-resources.c: src/nma.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) 
--generate-dependencies $(srcdir)/src/nma.gresource.xml |sed "s,^,$(builddir)/src/libnma-gtk4/,")
-       @mkdir -p $(builddir)/src/libnma-gtk4
+       @mkdir -p $(builddir)/src/libnma-gtk4 $(builddir)/src/libnma-gtk4/nma-ws
        $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) $< --target=$@ --sourcedir=$(builddir)/src/libnma-gtk4 
--generate-source --internal
 
 
 src/libnma-gtk4/%.ui: src/%.ui
-       @mkdir -p $(builddir)/src/libnma-gtk4
+       @mkdir -p $(builddir)/src/libnma-gtk4 $(builddir)/src/libnma-gtk4/nma-ws
        gtk4-builder-tool simplify --3to4 $< |awk '/^</ {xml=1} {if (xml) print; else print >"/dev/stderr"}' 
$@
 
 CLEANFILES += \
@@ -284,7 +284,16 @@ 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-802-1x.h \
+       src/nma-ws/nma-ws-dynamic-wep.h \
+       src/nma-ws/nma-ws.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
 
 libnma_c_real = \
        src/nma-wifi-dialog.c \
@@ -296,7 +305,24 @@ 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-eap.c \
+       src/nma-ws/nma-eap-fast.c \
+       src/nma-ws/nma-eap-leap.c \
+       src/nma-ws/nma-eap-peap.c \
+       src/nma-ws/nma-eap-simple.c \
+       src/nma-ws/nma-eap-tls.c \
+       src/nma-ws/nma-eap-ttls.c \
+       src/nma-ws/nma-ws-802-1x.c \
+       src/nma-ws/nma-ws.c \
+       src/nma-ws/nma-ws-dynamic-wep.c \
+       src/nma-ws/nma-ws-helpers.c \
+       src/nma-ws/nma-ws-leap.c \
+       src/nma-ws/nma-ws-sae.c \
+       src/nma-ws/nma-ws-wep-key.c \
+       src/nma-ws/nma-ws-wpa-eap.c \
+       src/nma-ws/nma-ws-wpa-psk.c
 
 EXTRA_DIST += \
        src/qrcodegen.c \
@@ -304,7 +330,17 @@ EXTRA_DIST += \
 
 libnma_h_priv_real = \
        src/nma-cert-chooser-private.h \
-       src/nma-private.h
+       src/nma-private.h \
+       src/nma-ws/nma-ws-private.h \
+       src/nma-ws/nma-ws-802-1x-private.h \
+       src/nma-ws/nma-eap.h \
+       src/nma-ws/nma-eap-tls.h \
+       src/nma-ws/nma-eap-leap.h \
+       src/nma-ws/nma-eap-fast.h \
+       src/nma-ws/nma-eap-ttls.h \
+       src/nma-ws/nma-eap-peap.h \
+       src/nma-ws/nma-eap-simple.h \
+       src/nma-ws/nma-ws-helpers.h
 
 libnma_h_priv_gcr = \
        src/nma-pkcs11-token-login-dialog.h \
@@ -545,6 +581,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) \
@@ -747,7 +784,20 @@ 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-802-1x.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-psk.ui \
+       src/nma-ws/meson.build
 
 ###############################################################################
 
@@ -792,6 +842,7 @@ IGNORE_HFILES = \
        nma-pkcs11-token-login-dialog.h \
        nma-pkcs11-cert-chooser-dialog.h \
        nma-cert-chooser-button.h \
+       nma-eap.h \
        eap-method.h \
        wireless-security.h
 
diff --git a/NEWS b/NEWS
index 969f0e20..6bfc9876 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,10 @@
+=======================================================
+libnma-1.8.28
+Overview of changes since network-manager-applet-1.8.26
+=======================================================
+
+* Turned the wireless-security library to a public API
+
 =======================================================
 libnma-1.8.26
 Overview of changes since network-manager-applet-1.8.24
diff --git a/meson.build b/meson.build
index 75214c41..41724fa8 100644
--- a/meson.build
+++ b/meson.build
@@ -312,6 +312,7 @@ if enable_gtk_doc
     'nma-resources.h',
     'nma-private.h',
     'nma-version.h',
+    'nma-eap.h',
     'eap-method.h',
     'wireless-security.h',
   ]
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 67777098..87c2a3de 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -17,6 +17,33 @@ src/nma-ui-utils.c
 src/nma-vpn-password-dialog.c
 src/nma-vpn-password-dialog.ui
 src/nma-wifi-dialog.c
+src/nma-ws/nma-eap.c
+src/nma-ws/nma-eap-fast.c
+src/nma-ws/nma-eap-fast.ui
+src/nma-ws/nma-eap-leap.c
+src/nma-ws/nma-eap-leap.ui
+src/nma-ws/nma-eap-peap.c
+src/nma-ws/nma-eap-peap.ui
+src/nma-ws/nma-eap-simple.c
+src/nma-ws/nma-eap-simple.ui
+src/nma-ws/nma-eap-tls.c
+src/nma-ws/nma-eap-tls.ui
+src/nma-ws/nma-eap-ttls.c
+src/nma-ws/nma-eap-ttls.ui
+src/nma-ws/nma-ws-802-1x.c
+src/nma-ws/nma-ws-802-1x.ui
+src/nma-ws/nma-ws.c
+src/nma-ws/nma-ws-dynamic-wep.c
+src/nma-ws/nma-ws-helpers.c
+src/nma-ws/nma-ws-leap.c
+src/nma-ws/nma-ws-leap.ui
+src/nma-ws/nma-ws-sae.c
+src/nma-ws/nma-ws-sae.ui
+src/nma-ws/nma-ws-wep-key.c
+src/nma-ws/nma-ws-wep-key.ui
+src/nma-ws/nma-ws-wpa-eap.c
+src/nma-ws/nma-ws-wpa-psk.c
+src/nma-ws/nma-ws-wpa-psk.ui
 src/wifi.ui
 src/utils/utils.c
 src/wireless-security/eap-method.c
diff --git a/src/libnma.ver b/src/libnma.ver
index 9b263d9c..3e444d44 100644
--- a/src/libnma.ver
+++ b/src/libnma.ver
@@ -112,3 +112,25 @@ libnma_1_8_22 {
        nma_bar_code_widget_get_type;
        nma_bar_code_widget_new;
 } libnma_1_8_12;
+
+libnma_1_8_28 {
+       nma_ws_802_1x_get_type;
+       nma_ws_802_1x_new;
+       nma_ws_add_to_size_group;
+       nma_ws_adhoc_compatible;
+       nma_ws_dynamic_wep_get_type;
+       nma_ws_dynamic_wep_new;
+       nma_ws_fill_connection;
+       nma_ws_get_type;
+       nma_ws_leap_get_type;
+       nma_ws_leap_new;
+       nma_ws_sae_get_type;
+       nma_ws_sae_new;
+       nma_ws_validate;
+       nma_ws_wep_key_get_type;
+       nma_ws_wep_key_new;
+       nma_ws_wpa_eap_get_type;
+       nma_ws_wpa_eap_new;
+       nma_ws_wpa_psk_get_type;
+       nma_ws_wpa_psk_new;
+} libnma_1_8_22;
diff --git a/src/meson.build b/src/meson.build
index d1dbeb54..58948758 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -16,6 +16,7 @@ version_header = configure_file(
 
 subdir('utils')
 subdir('wireless-security')
+subdir('nma-ws')
 
 cert_chooser_headers = files('nma-cert-chooser.h')
 
@@ -24,7 +25,7 @@ cert_chooser_sources = files(
   'nma-file-cert-chooser.c'
 )
 
-resource_data = files(
+resource_data = nma_ws_resource_data + files(
   'nma-bar-code-widget.ui',
   'nma-mobile-wizard.ui',
   'nma-pkcs11-cert-chooser-dialog.ui',
@@ -39,7 +40,7 @@ built_sources = gnome.compile_resources(
   dependencies: resource_data
 )
 
-gir_headers = cert_chooser_headers + files(
+gir_headers = cert_chooser_headers + nma_ws_headers + files(
   'nma-bar-code-widget.h',
   'nma-bar-code.h',
   'nma-mobile-providers.h',
@@ -54,7 +55,7 @@ install_headers(
   subdir: 'libnma'
 )
 
-gir_sources = [version_header] + cert_chooser_sources + files(
+gir_sources = [version_header] + cert_chooser_sources + nma_ws_sources + files(
   'init.c',
   'nma-bar-code-widget.c',
   'nma-bar-code.c',
@@ -69,7 +70,8 @@ incs = [
   top_inc,
   shared_inc,
   src_inc,
-  wireless_security_inc
+  wireless_security_inc,
+  nma_ws_inc,
 ]
 
 deps = [
diff --git a/src/nma-version.h.in b/src/nma-version.h.in
index cd9f2d57..1ba9382e 100644
--- a/src/nma-version.h.in
+++ b/src/nma-version.h.in
@@ -118,4 +118,10 @@
 # define NMA_AVAILABLE_IN_1_8_22
 #endif
 
+#if NMA_VERSION_MAX_ALLOWED < NMA_VERSION_1_8_28
+# define NMA_AVAILABLE_IN_1_8_28            G_UNAVAILABLE(1.8,28)
+#else
+# define NMA_AVAILABLE_IN_1_8_28
+#endif
+
 #endif  /* NMA_VERSION_H */
diff --git a/src/nma-ws/meson.build b/src/nma-ws/meson.build
new file mode 100644
index 00000000..7b94d4be
--- /dev/null
+++ b/src/nma-ws/meson.build
@@ -0,0 +1,45 @@
+nma_ws_inc = include_directories('.')
+
+nma_ws_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',
+  'nma-ws-802-1x.ui',
+  'nma-ws-leap.ui',
+  'nma-ws-sae.ui',
+  'nma-ws-wep-key.ui',
+  'nma-ws-wpa-psk.ui',
+)
+
+nma_ws_headers = files(
+  'nma-ws-802-1x.h',
+  'nma-ws-dynamic-wep.h',
+  'nma-ws.h',
+  'nma-ws-leap.h',
+  'nma-ws-sae.h',
+  'nma-ws-wep-key.h',
+  'nma-ws-wpa-eap.h',
+  'nma-ws-wpa-psk.h',
+)
+
+nma_ws_sources = 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',
+  'nma-ws-802-1x.c',
+  'nma-ws.c',
+  'nma-ws-dynamic-wep.c',
+  'nma-ws-helpers.c',
+  'nma-ws-leap.c',
+  'nma-ws-sae.c',
+  'nma-ws-wep-key.c',
+  'nma-ws-wpa-eap.c',
+  'nma-ws-wpa-psk.c',
+)
diff --git a/src/nma-ws/nma-eap-fast.c b/src/nma-ws/nma-eap-fast.c
new file mode 100644
index 00000000..c3b3e42a
--- /dev/null
+++ b/src/nma-ws/nma-eap-fast.c
@@ -0,0 +1,438 @@
+// 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 "nma-ws-private.h"
+#include "utils.h"
+
+#define I_NAME_COLUMN   0
+#define I_METHOD_COLUMN 1
+
+struct _NMAEapFast {
+       NMAEap parent;
+
+       const char *password_flags_name;
+       GtkSizeGroup *size_group;
+       NMAWs8021x *ws_8021x;
+       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->ws_8021x);
+}
+
+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->ws_8021x,
+                                       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->ws_8021x,
+                                             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->ws_8021x);
+}
+
+NMAEapFast *
+nma_eap_fast_new (NMAWs8021x *ws_8021x,
+                  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_grid",
+                              "eap_fast_anon_identity_entry",
+                              FALSE);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapFast *) parent;
+       method->password_flags_name = NM_SETTING_802_1X_PASSWORD;
+       method->ws_8021x = ws_8021x;
+       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_8021x);
+
+       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_8021x);
+
+       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_8021x);
+
+       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..a63d9707
--- /dev/null
+++ b/src/nma-ws/nma-eap-fast.h
@@ -0,0 +1,20 @@
+// 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 (NMAWs8021x *ws_8021x,
+                              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..261206b5
--- /dev/null
+++ b/src/nma-ws/nma-eap-fast.ui
@@ -0,0 +1,166 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <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="GtkGrid" id="eap_fast_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_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="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</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>
+</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..d0929efc
--- /dev/null
+++ b/src/nma-ws/nma-eap-leap.c
@@ -0,0 +1,257 @@
+// 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-ws-private.h"
+#include "nma-ws-helpers.h"
+#include "nma-ws-802-1x.h"
+#include "nma-ws-802-1x-private.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+struct _NMAEapLeap {
+       NMAEap parent;
+
+       NMAWs8021x *ws_8021x;
+
+       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)
+{
+       nma_ws_helper_fill_secret_entry (connection,
+                                        GTK_EDITABLE (gtk_builder_get_object (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_8021x. */
+static void
+set_userpass_ui (NMAEapLeap *method)
+{
+       if (method->ws_8021x->username) {
+               gtk_editable_set_text (GTK_EDITABLE (method->username_entry),
+                                      method->ws_8021x->username);
+       } else {
+               gtk_editable_set_text (GTK_EDITABLE (method->username_entry), "");
+       }
+
+       if (method->ws_8021x->password && !method->ws_8021x->always_ask) {
+               gtk_editable_set_text (GTK_EDITABLE (method->password_entry),
+                                      method->ws_8021x->password);
+       } else {
+               gtk_editable_set_text (GTK_EDITABLE (method->password_entry), "");
+       }
+
+       gtk_toggle_button_set_active (method->show_password, method->ws_8021x->show_password);
+}
+
+static void
+widgets_realized (GtkWidget *widget, NMAEapLeap *method)
+{
+       set_userpass_ui (method);
+}
+
+static void
+widgets_unrealized (GtkWidget *widget, NMAEapLeap *method)
+{
+       nma_ws_802_1x_set_userpass (method->ws_8021x,
+                            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_grid"));
+       g_assert (widget);
+       g_signal_handlers_disconnect_by_data (widget, method);
+
+       g_signal_handlers_disconnect_by_data (method->username_entry, method->ws_8021x);
+       g_signal_handlers_disconnect_by_data (method->password_entry, method->ws_8021x);
+       g_signal_handlers_disconnect_by_data (method->show_password, method);
+}
+
+NMAEapLeap *
+nma_eap_leap_new (NMAWs8021x *ws_8021x,
+                     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_grid",
+                              "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_8021x = ws_8021x;
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_leap_grid"));
+       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_8021x);
+
+       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_8021x);
+
+       /* 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_8021x.
+        * 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..c75aa56a
--- /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 (NMAWs8021x *ws_8021x,
+                              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..1794ada2
--- /dev/null
+++ b/src/nma-ws/nma-eap-leap.ui
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkGrid" id="eap_leap_grid">
+    <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>
+</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..3f96c46d
--- /dev/null
+++ b/src/nma-ws/nma-eap-peap.c
@@ -0,0 +1,486 @@
+// 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-ws-private.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;
+       NMAWs8021x *ws_8021x;
+       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;
+       NMSettingSecretFlags secret_flags;
+
+       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);
+
+       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);
+
+       /* 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);
+       }
+
+       /* 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->ws_8021x);
+}
+
+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->ws_8021x,
+                                          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->ws_8021x,
+                                    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->ws_8021x,
+                                    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 (NMAWs8021x *ws_8021x,
+                  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_grid",
+                              "eap_peap_anon_identity_entry",
+                              FALSE);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapPeap *) parent;
+       method->password_flags_name = NM_SETTING_802_1X_PASSWORD;
+       method->ws_8021x = ws_8021x;
+       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_8021x);
+
+       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_8021x);
+       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_8021x);
+
+       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_8021x);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_peap_domain_entry"));
+       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_8021x);
+
+       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..9f6c4a1e
--- /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 (NMAWs8021x *ws_8021x,
+                              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..b0b5c2c9
--- /dev/null
+++ b/src/nma-ws/nma-eap-peap.ui
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <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="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="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</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>
+</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..a26f6bda
--- /dev/null
+++ b/src/nma-ws/nma-eap-simple.c
@@ -0,0 +1,485 @@
+// 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-ws-private.h"
+#include "nma-ws-helpers.h"
+#include "nma-ws-802-1x.h"
+#include "nma-ws-802-1x-private.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+struct _NMAEapSimple {
+       NMAEap parent;
+
+       NMAWs8021x *ws_8021x;
+
+       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)
+{
+       nma_ws_helper_fill_secret_entry (connection,
+                                        GTK_EDITABLE (gtk_builder_get_object (parent->builder, 
"eap_simple_password_entry")),
+                                        NM_TYPE_SETTING_802_1X,
+                                        (HelperSecretFunc) nm_setting_802_1x_get_password);
+       nma_ws_helper_fill_secret_entry (connection,
+                                        GTK_EDITABLE (gtk_builder_get_object (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_8021x);
+       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_8021x. */
+static void
+set_userpass_ui (NMAEapSimple *method)
+{
+       if (method->ws_8021x->username) {
+               gtk_editable_set_text (GTK_EDITABLE (method->username_entry),
+                                      method->ws_8021x->username);
+       } else {
+               gtk_editable_set_text (GTK_EDITABLE (method->username_entry), "");
+       }
+
+       if (method->ws_8021x->password && !method->ws_8021x->always_ask) {
+               gtk_editable_set_text (GTK_EDITABLE (method->password_entry),
+                                                    method->ws_8021x->password);
+       } else {
+               gtk_editable_set_text (GTK_EDITABLE (method->password_entry), "");
+       }
+
+       gtk_toggle_button_set_active (method->show_password, method->ws_8021x->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_802_1x_set_userpass (method->ws_8021x,
+                            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_grid"));
+       g_assert (widget);
+       g_signal_handlers_disconnect_by_data (widget, method);
+
+       g_signal_handlers_disconnect_by_data (method->username_entry, method->ws_8021x);
+       g_signal_handlers_disconnect_by_data (method->password_entry, method->ws_8021x);
+       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_8021x);
+       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 (NMAWs8021x *ws_8021x,
+                    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_grid",
+                              "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_8021x = ws_8021x;
+       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_grid"));
+       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_8021x);
+
+       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_8021x);
+
+       /* 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_8021x);
+
+       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_8021x.
+        * 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..82024dca
--- /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 (NMAWs8021x *ws_8021x,
+                                  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..e364a65a
--- /dev/null
+++ b/src/nma-ws/nma-eap-simple.ui
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <requires lib="gtk+" version="3.10"/>
+  <object class="GtkGrid" id="eap_simple_grid">
+    <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="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</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>
+</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..5f671fab
--- /dev/null
+++ b/src/nma-ws/nma-eap-tls.c
@@ -0,0 +1,497 @@
+// 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 "nma-ws-private.h"
+#include "nma-ui-utils.h"
+#include "nma-cert-chooser.h"
+#include "utils.h"
+
+struct _NMAEapTls {
+       NMAEap parent;
+
+       const char *ca_cert_password_flags_name;
+       const char *client_cert_password_flags_name;
+       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);
+
+       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);
+
+       /* 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);
+
+       /* 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);
+       }
+
+       /* 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 (NMAWs8021x *ws_8021x,
+                 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_grid",
+                              "eap_tls_identity_entry",
+                              phase2);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapTls *) parent;
+       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;
+       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_8021x);
+
+       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_8021x);
+       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);
+       g_signal_connect (G_OBJECT (widget), "changed",
+                         (GCallback) nma_ws_changed_cb,
+                         ws_8021x);
+       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));
+       }
+
+       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_8021x);
+
+       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_8021x);
+       g_signal_connect (method->client_cert_chooser,
+                         "changed",
+                         G_CALLBACK (nma_ws_changed_cb),
+                         ws_8021x);
+
+       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 */
+       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);
+       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..5de30814
--- /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-802-1x.h"
+
+typedef struct _NMAEapTls NMAEapTls;
+
+NMAEapTls *nma_eap_tls_new (NMAWs8021x *ws_8021x,
+                            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..1705f26f
--- /dev/null
+++ b/src/nma-ws/nma-eap-tls.ui
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <requires lib="gtk+" version="3.10"/>
+  <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>
+</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..fee809f8
--- /dev/null
+++ b/src/nma-ws/nma-eap-ttls.c
@@ -0,0 +1,521 @@
+// 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-ws-private.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;
+       NMAWs8021x *ws_8021x;
+       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;
+       NMSettingSecretFlags secret_flags;
+       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);
+
+       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);
+
+       /* 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);
+       }
+
+       /* 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->ws_8021x);
+}
+
+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->ws_8021x,
+                                    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->ws_8021x,
+                                       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->ws_8021x,
+                                          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->ws_8021x,
+                                                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->ws_8021x,
+                                     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->ws_8021x,
+                                    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->ws_8021x,
+                                    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 (NMAWs8021x *ws_8021x,
+                     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_grid",
+                              "eap_ttls_anon_identity_entry",
+                              FALSE);
+       if (!parent)
+               return NULL;
+
+       method = (NMAEapTtls *) parent;
+       method->password_flags_name = NM_SETTING_802_1X_PASSWORD;
+       method->ws_8021x = ws_8021x;
+       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_8021x);
+
+       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_8021x);
+       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_8021x);
+
+       widget = GTK_WIDGET (gtk_builder_get_object (parent->builder, "eap_ttls_domain_entry"));
+       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_8021x);
+
+       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);
+       }
+
+       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);
+
+       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..1e072336
--- /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 (NMAWs8021x *ws_8021x,
+                              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..0fe6384f
--- /dev/null
+++ b/src/nma-ws/nma-eap-ttls.ui
@@ -0,0 +1,148 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <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="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="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</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>
+</interface>
diff --git a/src/nma-ws/nma-eap.c b/src/nma-ws/nma-eap.c
new file mode 100644
index 00000000..f666dab9
--- /dev/null
+++ b/src/nma-ws/nma-eap.c
@@ -0,0 +1,424 @@
+// 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"
+
+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;
+               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;
+               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;
+               case NM_SETTING_802_1X_CK_SCHEME_PKCS11:
+                       value = key_uri_func (s_8021x);
+                       break;
+               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..db5c84a0
--- /dev/null
+++ b/src/nma-ws/nma-eap.h
@@ -0,0 +1,106 @@
+// 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);
+
+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-802-1x-private.h b/src/nma-ws/nma-ws-802-1x-private.h
new file mode 100644
index 00000000..23743eee
--- /dev/null
+++ b/src/nma-ws/nma-ws-802-1x-private.h
@@ -0,0 +1,37 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_802_1X_PRIVATE_H
+#define NMA_WS_802_1X_PRIVATE_H
+
+struct _NMAWs8021xClass {
+       GtkGridClass parent;
+};
+
+struct _NMAWs8021x {
+       GtkGrid parent;
+
+       GtkWidget *eap_auth_combo;
+       GtkWidget *eap_auth_label;
+       GtkWidget *eap_vbox;
+
+       NMConnection *connection;
+       gboolean secrets_only;
+       gboolean is_editor;
+       char **secrets_hints;
+
+       char *username, *password;
+       gboolean always_ask, show_password;
+};
+
+void nma_ws_802_1x_fill_connection (NMAWs *ws, NMConnection *connection);
+
+void nma_ws_802_1x_set_userpass (NMAWs8021x *self,
+                                 const char *user,
+                                 const char *password,
+                                 gboolean always_ask,
+                                 gboolean show_password);
+
+#endif /* NMA_WS_802_1X_PRIVATE_H */
diff --git a/src/nma-ws/nma-ws-802-1x.c b/src/nma-ws/nma-ws-802-1x.c
new file mode 100644
index 00000000..ba348266
--- /dev/null
+++ b/src/nma-ws/nma-ws-802-1x.c
@@ -0,0 +1,528 @@
+// 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 "nma-ws-private.h"
+#include "nma-ws-802-1x.h"
+#include "nma-ws-802-1x-private.h"
+#include "nma-ws-helpers.h"
+#include "nma-ui-utils.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"
+#include "nma-eap.h"
+
+#include "utils.h"
+
+#define AUTH_NAME_COLUMN   0
+#define AUTH_METHOD_COLUMN 1
+
+static void nma_ws_interface_init (NMAWsInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NMAWs8021x, nma_ws_802_1x, GTK_TYPE_GRID,
+                         G_IMPLEMENT_INTERFACE (NMA_TYPE_WS, nma_ws_interface_init))
+
+enum {
+       PROP_0,
+       PROP_CONNECTION,
+       PROP_SECRETS_ONLY,
+       PROP_IS_EDITOR,
+       PROP_SECRETS_HINTS,
+       PROP_LAST
+};
+
+void
+nma_ws_802_1x_set_userpass (NMAWs8021x *self,
+                            const char *user,
+                            const char *password,
+                            gboolean always_ask,
+                            gboolean show_password)
+{
+       g_free (self->username);
+       self->username = g_strdup (user);
+
+       if (self->password) {
+               memset (self->password, 0, strlen (self->password));
+               g_free (self->password);
+       }
+       self->password = g_strdup (password);
+
+       if (always_ask != (gboolean) -1)
+               self->always_ask = always_ask;
+       self->show_password = show_password;
+}
+
+static void
+init_userpass (NMAWs8021x *self, 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_802_1x_set_userpass (self, user, password, always_ask, show_password);
+}
+
+static gboolean
+validate (NMAWs *ws, GError **error)
+{
+       NMAWs8021x *self = NMA_WS_802_1X (ws);
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       NMAEap *eap = NULL;
+       gboolean valid = FALSE;
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (self->eap_auth_combo));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->eap_auth_combo), &iter);
+       gtk_tree_model_get (model, &iter, AUTH_METHOD_COLUMN, &eap, -1);
+       g_return_val_if_fail (eap, FALSE);
+       valid = nma_eap_validate (eap, error);
+       nma_eap_unref (eap);
+       return valid;
+}
+
+static void
+auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
+{
+       NMAWs8021x *self = NMA_WS_802_1X (user_data);
+
+       NMAEap *eap = NULL;
+       GList *elt, *children;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+       GtkWidget *eap_widget;
+       GtkWidget *eap_default_widget = NULL;
+
+       /* Remove any previous wireless security widgets */
+       children = gtk_container_get_children (GTK_CONTAINER (self->eap_vbox));
+       for (elt = children; elt; elt = g_list_next (elt))
+               gtk_container_remove (GTK_CONTAINER (self->eap_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_return_if_fail (eap);
+
+       eap_widget = nma_eap_get_widget (eap);
+       g_return_if_fail (eap_widget);
+       gtk_widget_unparent (eap_widget);
+
+       gtk_container_add (GTK_CONTAINER (self->eap_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 (self));
+}
+
+static void
+add_to_size_group (NMAWs *ws, GtkSizeGroup *group)
+{
+       NMAWs8021x *self = NMA_WS_802_1X (ws);
+       NMAEap *eap = NULL;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (self->eap_auth_combo));
+
+       /* 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_add_to_size_group (eap, group);
+                               nma_eap_unref (eap);
+                       }
+               } while (gtk_tree_model_iter_next (model, &iter));
+       }
+
+       gtk_size_group_add_widget (group, self->eap_auth_label);
+}
+
+void
+nma_ws_802_1x_fill_connection (NMAWs *ws, NMConnection *connection)
+{
+       NMAWs8021x *self = NMA_WS_802_1X (ws);
+       NMSettingWirelessSecurity *s_wireless_sec;
+       NMSetting8021x *s_8021x;
+       NMAEap *eap = NULL;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+
+       /* Get the NMAEap object */
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (self->eap_auth_combo));
+       gtk_combo_box_get_active_iter (GTK_COMBO_BOX (self->eap_auth_combo), &iter);
+       gtk_tree_model_get (model, &iter, AUTH_METHOD_COLUMN, &eap, -1);
+       g_return_if_fail (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);
+}
+
+static void
+update_secrets (NMAWs *ws, NMConnection *connection)
+{
+       NMAWs8021x *self = NMA_WS_802_1X (ws);
+       NMAEap *eap = NULL;
+       GtkTreeModel *model;
+       GtkTreeIter iter;
+
+       g_return_if_fail (connection != NULL);
+
+       model = gtk_combo_box_get_model (GTK_COMBO_BOX (self->eap_auth_combo));
+
+       /* 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));
+       }
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWs8021x *self = NMA_WS_802_1X (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               g_value_set_object (value, self->connection);
+               break;
+       case PROP_SECRETS_ONLY:
+               g_value_set_boolean (value, self->secrets_only);
+               break;
+       case PROP_IS_EDITOR:
+               g_value_set_boolean (value, self->is_editor);
+               break;
+       case PROP_SECRETS_HINTS:
+               g_value_set_boxed (value, self->secrets_hints);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+set_property (GObject *object,
+              guint prop_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWs8021x *self = NMA_WS_802_1X (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               self->connection = g_value_dup_object (value);
+               break;
+       case PROP_SECRETS_ONLY:
+               self->secrets_only = g_value_get_boolean (value);
+               break;
+       case PROP_IS_EDITOR:
+               self->is_editor = g_value_get_boolean (value);
+               break;
+       case PROP_SECRETS_HINTS:
+               self->secrets_hints = g_value_dup_boxed (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+nma_ws_802_1x_init (NMAWs8021x *self)
+{
+       gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+nma_ws_interface_init (NMAWsInterface *iface)
+{
+       iface->validate = validate;
+       iface->add_to_size_group = add_to_size_group;
+       iface->fill_connection = nma_ws_802_1x_fill_connection;
+       iface->update_secrets = update_secrets;
+       iface->adhoc_compatible = FALSE;
+       iface->hotspot_compatible = FALSE;
+}
+
+static void
+constructed (GObject *object)
+{
+       NMAWs8021x *self = NMA_WS_802_1X (object);
+       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 (self->connection) {
+               NMSettingConnection *s_con;
+               NMSetting8021x *s_8021x;
+
+               s_con = nm_connection_get_setting_connection (self->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 (self->connection))
+                       wired = TRUE;
+
+               s_8021x = nm_connection_get_setting_802_1x (self->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) */
+       init_userpass (self, self->connection);
+
+       auth_model = gtk_list_store_new (2, G_TYPE_STRING, nma_eap_get_type ());
+
+       if (self->is_editor)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_IS_EDITOR;
+       if (self->secrets_only)
+               simple_flags |= NMA_EAP_SIMPLE_FLAG_SECRETS_ONLY;
+
+       if (wired) {
+               em_md5 = nma_eap_simple_new (self, self->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 (self, self->connection, FALSE, self->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 (self, self->connection, self->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 (self, self->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 (self, self->connection, self->is_editor, self->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 (self, self->connection, self->is_editor, self->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 (self, self->connection, self->is_editor, self->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 (self->secrets_hints && self->secrets_hints[0]) {
+               NMAEapSimple *em_hints;
+
+               em_hints = nma_eap_simple_new (self, self->connection, NMA_EAP_SIMPLE_TYPE_UNKNOWN,
+                                              simple_flags, (const char **)self->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 (self, self->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++;
+       }
+
+       gtk_combo_box_set_model (GTK_COMBO_BOX (self->eap_auth_combo), GTK_TREE_MODEL (auth_model));
+       g_object_unref (G_OBJECT (auth_model));
+       gtk_combo_box_set_active (GTK_COMBO_BOX (self->eap_auth_combo), active < 0 ? 0 : (guint32) active);
+
+       if (self->secrets_only) {
+               gtk_widget_hide (self->eap_auth_combo);
+               gtk_widget_hide (self->eap_auth_label);
+       }
+
+       G_OBJECT_CLASS (nma_ws_802_1x_parent_class)->constructed (object);
+}
+
+NMAWs8021x *
+nma_ws_802_1x_new (NMConnection *connection,
+                   gboolean is_editor,
+                   gboolean secrets_only)
+{
+       return g_object_new (NMA_TYPE_WS_802_1X,
+                            "connection", connection,
+                            "is-editor", is_editor,
+                            "secrets-only", secrets_only,
+                            NULL);
+}
+
+static void
+dispose (GObject *object)
+{
+       NMAWs8021x *self = NMA_WS_802_1X (object);
+
+       g_clear_object (&self->connection);
+       g_clear_pointer (&self->secrets_hints, g_strfreev);
+       g_clear_pointer (&self->username, g_free);
+       g_clear_pointer (&self->password, g_free);
+}
+
+static void
+nma_ws_802_1x_class_init (NMAWs8021xClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->get_property = get_property;
+       object_class->set_property = set_property;
+       object_class->constructed = constructed;
+       object_class->dispose = dispose;
+
+       g_object_class_override_property (object_class,
+                                         PROP_CONNECTION, "connection");
+
+       g_object_class_override_property (object_class,
+                                         PROP_SECRETS_ONLY, "secrets-only");
+
+       g_object_class_install_property
+               (object_class, PROP_IS_EDITOR,
+                g_param_spec_boolean ("is-editor", "", "",
+                                      FALSE,
+                                        G_PARAM_READWRITE
+                                      | G_PARAM_CONSTRUCT
+                                      | G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property
+               (object_class, PROP_SECRETS_HINTS,
+                g_param_spec_boxed ("secrets-hints", "", "",
+                                    G_TYPE_STRV,
+                                      G_PARAM_READWRITE
+                                    | G_PARAM_CONSTRUCT
+                                    | G_PARAM_STATIC_STRINGS));
+
+       gtk_widget_class_set_template_from_resource (widget_class,
+                                                    "/org/gnome/libnma/nma-ws-802-1x.ui");
+
+       gtk_widget_class_bind_template_child (widget_class, NMAWs8021x, eap_auth_combo);
+       gtk_widget_class_bind_template_child (widget_class, NMAWs8021x, eap_auth_label);
+       gtk_widget_class_bind_template_child (widget_class, NMAWs8021x, eap_vbox);
+
+       gtk_widget_class_bind_template_callback (widget_class, auth_combo_changed_cb);
+}
diff --git a/src/nma-ws/nma-ws-802-1x.h b/src/nma-ws/nma-ws-802-1x.h
new file mode 100644
index 00000000..c12c61f0
--- /dev/null
+++ b/src/nma-ws/nma-ws-802-1x.h
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_802_1X_H
+#define NMA_WS_802_1X_H
+
+#include "nma-version.h"
+
+G_BEGIN_DECLS
+
+typedef struct _NMAWs8021xClass NMAWs8021xClass;
+typedef struct _NMAWs8021x NMAWs8021x;
+
+#define NMA_TYPE_WS_802_1X            (nma_ws_802_1x_get_type ())
+#define NMA_WS_802_1X(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMA_TYPE_WS_802_1X, NMAWs8021x))
+#define NMA_WS_802_1X_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMA_TYPE_WS_802_1X, 
NMAWs8021xClass))
+#define NMA_IS_WS_802_1X(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMA_TYPE_WS_802_1X))
+#define NMA_IS_WS_802_1X_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMA_TYPE_WS_802_1X))
+#define NMA_WS_802_1X_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMA_TYPE_WS_802_1X, 
NMAWs8021xClass))
+
+NMA_AVAILABLE_IN_1_8_28
+GType nma_ws_802_1x_get_type (void);
+
+NMA_AVAILABLE_IN_1_8_28
+NMAWs8021x *nma_ws_802_1x_new (NMConnection *connection,
+                               gboolean is_editor,
+                               gboolean secrets_only);
+
+G_END_DECLS
+
+#endif /* NMA_WS_802_1X_H */
diff --git a/src/nma-ws/nma-ws-802-1x.ui b/src/nma-ws/nma-ws-802-1x.ui
new file mode 100644
index 00000000..1930d7b4
--- /dev/null
+++ b/src/nma-ws/nma-ws-802-1x.ui
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <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>
+  <template class="NMAWs8021x" parent="GtkGrid">
+    <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_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">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="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>
+        <signal name="changed" handler="auth_combo_changed_cb" swapped="no"/>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkBox" id="eap_vbox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="hexpand">True</property>
+        <property name="orientation">vertical</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>
+  </template>
+</interface>
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..911d7db6
--- /dev/null
+++ b/src/nma-ws/nma-ws-dynamic-wep.c
@@ -0,0 +1,68 @@
+// 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 "nma-ws.h"
+#include "nma-ws-private.h"
+#include "nma-ws-802-1x.h"
+#include "nma-ws-802-1x-private.h"
+#include "nma-ws-dynamic-wep.h"
+
+typedef struct {
+       NMAWs8021xClass parent;
+} NMAWsDynamicWepClass;
+
+struct _NMAWsDynamicWep {
+       NMAWs8021x parent;
+};
+
+static void nma_ws_interface_init (NMAWsInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NMAWsDynamicWep, nma_ws_dynamic_wep, NMA_TYPE_WS_802_1X,
+                         G_IMPLEMENT_INTERFACE (NMA_TYPE_WS, nma_ws_interface_init))
+
+static void
+fill_connection (NMAWs *ws, NMConnection *connection)
+{
+       NMSettingWirelessSecurity *s_wireless_sec;
+
+       nma_ws_802_1x_fill_connection (ws, connection);
+
+       s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
+       g_return_if_fail (s_wireless_sec);
+
+       g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x", NULL);
+}
+
+static void
+nma_ws_dynamic_wep_init (NMAWsDynamicWep *self)
+{
+}
+
+static void
+nma_ws_interface_init (NMAWsInterface *iface)
+{
+       iface->fill_connection = fill_connection;
+}
+
+NMAWsDynamicWep *
+nma_ws_dynamic_wep_new (NMConnection *connection,
+                        gboolean is_editor,
+                        gboolean secrets_only)
+{
+       return g_object_new (NMA_TYPE_WS_DYNAMIC_WEP,
+                            "connection", connection,
+                            "secrets-only", secrets_only,
+                            "is-editor", is_editor,
+                            NULL);
+}
+
+static void
+nma_ws_dynamic_wep_class_init (NMAWsDynamicWepClass *klass)
+{
+}
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..9057c52c
--- /dev/null
+++ b/src/nma-ws/nma-ws-dynamic-wep.h
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_DYNAMIC_WEP_H
+#define NMA_WS_DYNAMIC_WEP_H
+
+#include "nma-version.h"
+
+G_BEGIN_DECLS
+
+typedef struct _NMAWsDynamicWep NMAWsDynamicWep;
+
+#define NMA_TYPE_WS_DYNAMIC_WEP            (nma_ws_dynamic_wep_get_type ())
+#define NMA_WS_DYNAMIC_WEP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMA_TYPE_WS_SAE, 
NMAWsDynamicWep))
+#define NMA_WS_DYNAMIC_WEP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMA_TYPE_WS_SAE, 
NMAWsDynamicWepClass))
+#define NMA_IS_WS_DYNAMIC_WEP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMA_TYPE_WS_SAE))
+#define NMA_IS_WS_DYNAMIC_WEP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMA_TYPE_WS_SAE))
+#define NMA_WS_DYNAMIC_WEP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMA_TYPE_WS_SAE, 
NMAWsDynamicWepClass))
+
+NMA_AVAILABLE_IN_1_8_28
+GType nma_ws_dynamic_wep_get_type (void);
+
+NMA_AVAILABLE_IN_1_8_28
+NMAWsDynamicWep *nma_ws_dynamic_wep_new (NMConnection *connection,
+                                         gboolean is_editor,
+                                         gboolean secrets_only);
+
+G_END_DECLS
+
+#endif /* NMA_WS_DYNAMIC_WEP_H */
diff --git a/src/nma-ws/nma-ws-helpers.c b/src/nma-ws/nma-ws-helpers.c
new file mode 100644
index 00000000..d517ae38
--- /dev/null
+++ b/src/nma-ws/nma-ws-helpers.c
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2009 - 2019 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+#include "nma-private.h"
+#include "nma-ws-helpers.h"
+
+void
+nma_ws_helper_fill_secret_entry (NMConnection *connection,
+                                 GtkEditable *entry,
+                                 GType setting_type,
+                                 HelperSecretFunc func)
+{
+       NMSetting *setting;
+       const char *tmp;
+
+       g_return_if_fail (connection != NULL);
+       g_return_if_fail (entry != NULL);
+       g_return_if_fail (func != NULL);
+
+       setting = nm_connection_get_setting (connection, setting_type);
+       if (setting) {
+               tmp = (*func) (setting);
+               if (tmp)
+                       gtk_editable_set_text (entry, tmp);
+       }
+}
diff --git a/src/nma-ws/nma-ws-helpers.h b/src/nma-ws/nma-ws-helpers.h
new file mode 100644
index 00000000..3f842646
--- /dev/null
+++ b/src/nma-ws/nma-ws-helpers.h
@@ -0,0 +1,18 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2009 - 2019 Red Hat, Inc.
+ */
+
+#ifndef _NMA_WS_HELPERS_H_
+#define _NMA_WS_HELPERS_H_
+
+typedef const char * (*HelperSecretFunc)(NMSetting *);
+
+void nma_ws_helper_fill_secret_entry (NMConnection *connection,
+                                      GtkEditable *entry,
+                                      GType setting_type,
+                                      HelperSecretFunc func);
+
+#endif  /* _NMA_WS_HELPERS_H_ */
diff --git a/src/nma-ws/nma-ws-leap.c b/src/nma-ws/nma-ws-leap.c
new file mode 100644
index 00000000..ef2cf8bf
--- /dev/null
+++ b/src/nma-ws/nma-ws-leap.c
@@ -0,0 +1,293 @@
+// 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 "nma-ws-private.h"
+#include "nma-ws-leap.h"
+#include "nma-ws-helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+typedef struct {
+       GtkGridClass parent;
+} NMAWsLeapClass;
+
+struct _NMAWsLeap {
+       GtkGrid parent;
+
+       GtkWidget *leap_username_entry;
+       GtkWidget *leap_password_entry;
+       GtkWidget *leap_username_label;
+       GtkWidget *leap_password_label;
+       GtkWidget *show_checkbutton_leap;
+
+       NMConnection *connection;
+       gboolean secrets_only;
+};
+
+static void nma_ws_interface_init (NMAWsInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NMAWsLeap, nma_ws_leap, GTK_TYPE_GRID,
+                         G_IMPLEMENT_INTERFACE (NMA_TYPE_WS, nma_ws_interface_init))
+
+enum {
+       PROP_0,
+       PROP_CONNECTION,
+       PROP_SECRETS_ONLY,
+       PROP_LAST
+};
+
+static void
+show_toggled_cb (GtkCheckButton *button, gpointer user_data)
+{
+       NMAWsLeap *self = NMA_WS_LEAP (user_data);
+       gboolean visible;
+
+       visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       gtk_entry_set_visibility (GTK_ENTRY (self->leap_password_entry), visible);
+}
+
+static gboolean
+validate (NMAWs *ws, GError **error)
+{
+       NMAWsLeap *self = NMA_WS_LEAP (ws);
+       NMSettingSecretFlags secret_flags;
+       const char *text;
+       gboolean ret = TRUE;
+
+       text = gtk_editable_get_text (GTK_EDITABLE (self->leap_username_entry));
+       if (!text || !strlen (text)) {
+               widget_set_error (self->leap_username_entry);
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing leap-username"));
+               ret = FALSE;
+       } else {
+               widget_unset_error (self->leap_username_entry);
+       }
+
+       secret_flags = nma_utils_menu_to_secret_flags (self->leap_password_entry);
+       text = gtk_editable_get_text (GTK_EDITABLE (self->leap_password_entry));
+
+       if (   secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED
+           || secret_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED
+           || (text && strlen (text))) {
+               widget_unset_error (self->leap_password_entry);
+       } else {
+               widget_set_error (self->leap_password_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 *ws, GtkSizeGroup *group)
+{
+       NMAWsLeap *self = NMA_WS_LEAP (ws);
+
+       gtk_size_group_add_widget (group, self->leap_username_label);
+       gtk_size_group_add_widget (group, self->leap_password_label);
+}
+
+static void
+fill_connection (NMAWs *ws, NMConnection *connection)
+{
+       NMAWsLeap *self = NMA_WS_LEAP (ws);
+       NMSettingWirelessSecurity *s_wireless_sec;
+       NMSettingSecretFlags secret_flags;
+       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);
+
+       leap_username = gtk_editable_get_text (GTK_EDITABLE (self->leap_username_entry));
+       leap_password = gtk_editable_get_text (GTK_EDITABLE (self->leap_password_entry));
+
+       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 (self->leap_password_entry);
+       nm_setting_set_secret_flags (NM_SETTING (s_wireless_sec), NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD,
+                                    secret_flags, NULL);
+
+       /* Update secret flags and popup when editing the connection */
+       if (!self->secrets_only) {
+               nma_utils_update_password_storage (self->leap_password_entry, secret_flags,
+                                                  NM_SETTING (s_wireless_sec),
+                                                  NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD);
+       }
+}
+
+static void
+update_secrets (NMAWs *ws, NMConnection *connection)
+{
+       NMAWsLeap *self = NMA_WS_LEAP (ws);
+
+       nma_ws_helper_fill_secret_entry (connection,
+                                        GTK_EDITABLE (self->leap_password_entry),
+                                        NM_TYPE_SETTING_WIRELESS_SECURITY,
+                                        (HelperSecretFunc) nm_setting_wireless_security_get_leap_password);
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWsLeap *self = NMA_WS_LEAP (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               g_value_set_object (value, self->connection);
+               break;
+       case PROP_SECRETS_ONLY:
+               g_value_set_boolean (value, self->secrets_only);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+set_property (GObject *object,
+              guint prop_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWsLeap *self = NMA_WS_LEAP (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               self->connection = g_value_dup_object (value);
+               break;
+       case PROP_SECRETS_ONLY:
+               self->secrets_only = g_value_get_boolean (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+nma_ws_leap_init (NMAWsLeap *self)
+{
+       gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+nma_ws_interface_init (NMAWsInterface *iface)
+{
+       iface->validate = validate;
+       iface->add_to_size_group = add_to_size_group;
+       iface->fill_connection = fill_connection;
+       iface->update_secrets = update_secrets;
+       iface->adhoc_compatible = FALSE;
+       iface->hotspot_compatible = FALSE;
+}
+
+static void
+constructed (GObject *object)
+{
+       NMAWsLeap *self = NMA_WS_LEAP (object);
+       NMSettingWirelessSecurity *wsec = NULL;
+
+       if (self->connection) {
+               wsec = nm_connection_get_setting_wireless_security (self->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;
+               }
+       }
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       nma_utils_setup_password_storage (self->leap_password_entry, 0, (NMSetting *) wsec,
+                                         NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD,
+                                         FALSE, self->secrets_only);
+
+       if (wsec) {
+               update_secrets (NMA_WS (self), self->connection);
+               gtk_editable_set_text (GTK_EDITABLE (self->leap_username_entry),
+                                      nm_setting_wireless_security_get_leap_username (wsec));
+       }
+
+       if (self->secrets_only) {
+               gtk_widget_hide (self->leap_username_label);
+               gtk_widget_hide (self->leap_username_entry);
+       }
+
+       gtk_widget_grab_focus (self->leap_password_entry);
+
+       G_OBJECT_CLASS (nma_ws_leap_parent_class)->constructed (object);
+}
+
+NMAWsLeap *
+nma_ws_leap_new (NMConnection *connection, gboolean secrets_only)
+{
+       return g_object_new (NMA_TYPE_WS_LEAP,
+                            "connection", connection,
+                            "secrets-only", secrets_only,
+                            NULL);
+}
+
+static void
+dispose (GObject *object)
+{
+       NMAWsLeap *self = NMA_WS_LEAP (object);
+
+       g_clear_object (&self->connection);
+}
+
+static void
+nma_ws_leap_class_init (NMAWsLeapClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->get_property = get_property;
+       object_class->set_property = set_property;
+       object_class->constructed = constructed;
+       object_class->dispose = dispose;
+
+       g_object_class_override_property (object_class,
+                                         PROP_CONNECTION, "connection");
+
+       g_object_class_override_property (object_class,
+                                         PROP_SECRETS_ONLY, "secrets-only");
+
+        gtk_widget_class_set_template_from_resource (widget_class,
+                                                     "/org/gnome/libnma/nma-ws-leap.ui");
+
+       gtk_widget_class_bind_template_child (widget_class, NMAWsLeap, leap_username_entry);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsLeap, leap_password_entry);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsLeap, leap_username_label);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsLeap, leap_password_label);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsLeap, show_checkbutton_leap);
+
+       gtk_widget_class_bind_template_callback (widget_class, nma_ws_changed_cb);
+       gtk_widget_class_bind_template_callback (widget_class, show_toggled_cb);
+}
diff --git a/src/nma-ws/nma-ws-leap.h b/src/nma-ws/nma-ws-leap.h
new file mode 100644
index 00000000..0f99bc12
--- /dev/null
+++ b/src/nma-ws/nma-ws-leap.h
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_LEAP_H
+#define NMA_WS_LEAP_H
+
+#include "nma-version.h"
+
+G_BEGIN_DECLS
+
+typedef struct _NMAWsLeap NMAWsLeap;
+
+#define NMA_TYPE_WS_LEAP            (nma_ws_leap_get_type ())
+#define NMA_WS_LEAP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMA_TYPE_WS_LEAP, NMAWsLeap))
+#define NMA_WS_LEAP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMA_TYPE_WS_LEAP, NMAWsLeapClass))
+#define NMA_IS_WS_LEAP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMA_TYPE_WS_LEAP))
+#define NMA_IS_WS_LEAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMA_TYPE_WS_LEAP))
+#define NMA_WS_LEAP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMA_TYPE_WS_LEAP, NMAWsLeapClass))
+
+NMA_AVAILABLE_IN_1_8_28
+GType nma_ws_leap_get_type (void);
+
+NMA_AVAILABLE_IN_1_8_28
+NMAWsLeap *nma_ws_leap_new (NMConnection *connection, gboolean secrets_only);
+
+G_END_DECLS
+
+#endif /* NMA_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..0a7197f7
--- /dev/null
+++ b/src/nma-ws/nma-ws-leap.ui
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <requires lib="gtk+" version="3.10"/>
+  <template class="NMAWsLeap" parent="GtkGrid">
+    <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>
+        <signal name="changed" handler="nma_ws_changed_cb" swapped="no"/>
+      </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>
+        <signal name="toggled" handler="show_toggled_cb" swapped="no"/>
+      </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>
+        <signal name="changed" handler="nma_ws_changed_cb" swapped="no"/>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">0</property>
+      </packing>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+  </template>
+</interface>
diff --git a/src/nma-ws/nma-ws-private.h b/src/nma-ws/nma-ws-private.h
new file mode 100644
index 00000000..63bb97f2
--- /dev/null
+++ b/src/nma-ws/nma-ws-private.h
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_PRIVATE_H
+#define NMA_WS_PRIVATE_H
+
+typedef struct {
+       GTypeInterface parent;
+
+       void (*add_to_size_group) (NMAWs *self, GtkSizeGroup *group);
+       void (*fill_connection)   (NMAWs *self, NMConnection *connection);
+       void (*update_secrets)    (NMAWs *self, NMConnection *connection);
+       gboolean (*validate)      (NMAWs *self, GError **error);
+
+       gboolean adhoc_compatible;
+       gboolean hotspot_compatible;
+} NMAWsInterface;
+
+void nma_ws_changed_cb (GtkWidget *entry, gpointer user_data);
+
+void nma_ws_clear_ciphers (NMConnection *connection);
+
+#endif /* NMA_WS_PRIVATE_H */
diff --git a/src/nma-ws/nma-ws-sae.c b/src/nma-ws/nma-ws-sae.c
new file mode 100644
index 00000000..a697b7c0
--- /dev/null
+++ b/src/nma-ws/nma-ws-sae.c
@@ -0,0 +1,285 @@
+// 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 "nma-ws-private.h"
+#include "nma-ws-sae.h"
+#include "nma-ws-helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+typedef struct {
+       GtkGridClass parent;
+} NMAWsSaeClass;
+
+struct _NMAWsSae {
+       GtkGrid parent;
+
+       GtkWidget *psk_entry;
+       GtkWidget *sae_label;
+       GtkWidget *sae_type_combo;
+       GtkWidget *sae_type_label;
+       GtkWidget *show_checkbutton_sae;
+
+       NMConnection *connection;
+       gboolean secrets_only;
+};
+
+static void nma_ws_interface_init (NMAWsInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NMAWsSae, nma_ws_sae, GTK_TYPE_GRID,
+                         G_IMPLEMENT_INTERFACE (NMA_TYPE_WS, nma_ws_interface_init))
+
+enum {
+       PROP_0,
+       PROP_CONNECTION,
+       PROP_SECRETS_ONLY,
+       PROP_LAST
+};
+
+static void
+show_toggled_cb (GtkCheckButton *button, gpointer user_data)
+{
+       NMAWsSae *self = NMA_WS_SAE (user_data);
+       gboolean visible;
+
+       visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       gtk_entry_set_visibility (GTK_ENTRY (self->psk_entry), visible);
+}
+
+static gboolean
+validate (NMAWs *ws, GError **error)
+{
+       NMAWsSae *self = NMA_WS_SAE (ws);
+       NMSettingSecretFlags secret_flags;
+       const char *key;
+
+       secret_flags = nma_utils_menu_to_secret_flags (self->psk_entry);
+       key = gtk_editable_get_text (GTK_EDITABLE (self->psk_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 (self->psk_entry);
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing password"));
+               return FALSE;
+       }
+       widget_unset_error (self->psk_entry);
+
+       return TRUE;
+}
+
+static void
+add_to_size_group (NMAWs *ws, GtkSizeGroup *group)
+{
+       NMAWsSae *self = NMA_WS_SAE (ws);
+
+       gtk_size_group_add_widget (group, self->sae_type_label);
+       gtk_size_group_add_widget (group, self->sae_label);
+}
+
+static void
+fill_connection (NMAWs *ws, NMConnection *connection)
+{
+       NMAWsSae *self = NMA_WS_SAE (ws);
+       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_return_if_fail (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);
+
+       key = gtk_editable_get_text (GTK_EDITABLE (self->psk_entry));
+       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 (self->psk_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 (!self->secrets_only) {
+               nma_utils_update_password_storage (self->psk_entry, secret_flags,
+                                                  NM_SETTING (s_wireless_sec),
+                                                  NM_SETTING_WIRELESS_SECURITY_PSK);
+       }
+
+       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 *ws, NMConnection *connection)
+{
+       NMAWsSae *self = NMA_WS_SAE (ws);
+
+       nma_ws_helper_fill_secret_entry (connection,
+                                        GTK_EDITABLE (self->psk_entry),
+                                        NM_TYPE_SETTING_WIRELESS_SECURITY,
+                                        (HelperSecretFunc) nm_setting_wireless_security_get_psk);
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWsSae *self = NMA_WS_SAE (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               g_value_set_object (value, self->connection);
+               break;
+       case PROP_SECRETS_ONLY:
+               g_value_set_boolean (value, self->secrets_only);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+set_property (GObject *object,
+              guint prop_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWsSae *self = NMA_WS_SAE (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               self->connection = g_value_dup_object (value);
+               break;
+       case PROP_SECRETS_ONLY:
+               self->secrets_only = g_value_get_boolean (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+nma_ws_sae_init (NMAWsSae *self)
+{
+       gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+nma_ws_interface_init (NMAWsInterface *iface)
+{
+       iface->validate = validate;
+       iface->add_to_size_group = add_to_size_group;
+       iface->fill_connection = fill_connection;
+       iface->update_secrets = update_secrets;
+       iface->adhoc_compatible = TRUE;
+       iface->hotspot_compatible = TRUE;
+}
+
+static void
+constructed (GObject *object)
+{
+       NMAWsSae *self = NMA_WS_SAE (object);
+       NMSetting *setting = NULL;
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       if (self->connection)
+               setting = (NMSetting *) nm_connection_get_setting_wireless_security (self->connection);
+       nma_utils_setup_password_storage (self->psk_entry, 0, setting, NM_SETTING_WIRELESS_SECURITY_PSK,
+                                         FALSE, self->secrets_only);
+
+       /* Fill secrets, if any */
+       if (self->connection)
+               update_secrets (NMA_WS (self), self->connection);
+
+       gtk_widget_grab_focus (self->psk_entry);
+
+       /* Hide WPA/RSN for now since this can be autodetected by NM and the
+        * supplicant when connecting to the AP.
+        */
+       gtk_widget_hide (self->sae_type_combo);
+       gtk_widget_hide (self->sae_type_label);
+
+       G_OBJECT_CLASS (nma_ws_sae_parent_class)->constructed (object);
+}
+
+NMAWsSae *
+nma_ws_sae_new (NMConnection *connection, gboolean secrets_only)
+{
+       return g_object_new (NMA_TYPE_WS_SAE,
+                            "connection", connection,
+                            "secrets-only", secrets_only,
+                            NULL);
+}
+
+static void
+dispose (GObject *object)
+{
+       NMAWsSae *self = NMA_WS_SAE (object);
+
+       g_clear_object (&self->connection);
+}
+
+static void
+nma_ws_sae_class_init (NMAWsSaeClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->get_property = get_property;
+       object_class->set_property = set_property;
+       object_class->constructed = constructed;
+       object_class->dispose = dispose;
+
+       g_object_class_override_property (object_class,
+                                         PROP_CONNECTION, "connection");
+
+       g_object_class_override_property (object_class,
+                                         PROP_SECRETS_ONLY, "secrets-only");
+
+        gtk_widget_class_set_template_from_resource (widget_class,
+                                                     "/org/gnome/libnma/nma-ws-sae.ui");
+
+       gtk_widget_class_bind_template_child (widget_class, NMAWsSae, psk_entry);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsSae, sae_label);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsSae, sae_type_combo);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsSae, sae_type_label);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsSae, show_checkbutton_sae);
+
+       gtk_widget_class_bind_template_callback (widget_class, nma_ws_changed_cb);
+       gtk_widget_class_bind_template_callback (widget_class, show_toggled_cb);
+}
diff --git a/src/nma-ws/nma-ws-sae.h b/src/nma-ws/nma-ws-sae.h
new file mode 100644
index 00000000..14baad4b
--- /dev/null
+++ b/src/nma-ws/nma-ws-sae.h
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_SAE_H
+#define NMA_WS_SAE_H
+
+#include "nma-version.h"
+
+G_BEGIN_DECLS
+
+typedef struct _NMAWsSae NMAWsSae;
+
+#define NMA_TYPE_WS_SAE            (nma_ws_sae_get_type ())
+#define NMA_WS_SAE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMA_TYPE_WS_SAE, NMAWsSae))
+#define NMA_WS_SAE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMA_TYPE_WS_SAE, NMAWsSaeClass))
+#define NMA_IS_WS_SAE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMA_TYPE_WS_SAE))
+#define NMA_IS_WS_SAE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMA_TYPE_WS_SAE))
+#define NMA_WS_SAE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMA_TYPE_WS_SAE, NMAWsSaeClass))
+
+NMA_AVAILABLE_IN_1_8_28
+GType nma_ws_sae_get_type (void);
+
+NMA_AVAILABLE_IN_1_8_28
+NMAWsSae *nma_ws_sae_new (NMConnection *connection, gboolean secrets_only);
+
+G_END_DECLS
+
+#endif /* NMA_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..80f3ee71
--- /dev/null
+++ b/src/nma-ws/nma-ws-sae.ui
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <requires lib="gtk+" version="3.10"/>
+  <template class="NMAWsSae" parent="GtkGrid">
+    <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>
+        <property name="width_chars">28</property>
+        <signal name="changed" handler="nma_ws_changed_cb" swapped="no"/>
+      </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>
+        <signal name="toggled" handler="show_toggled_cb" swapped="no"/>
+      </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>
+  </template>
+</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..6150d282
--- /dev/null
+++ b/src/nma-ws/nma-ws-wep-key.c
@@ -0,0 +1,457 @@
+// 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 "nma-ws-private.h"
+#include "nma-ws-wep-key.h"
+#include "nma-ws-helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+typedef struct {
+       GtkGridClass parent;
+} NMAWsWepKeyClass;
+
+struct _NMAWsWepKey {
+       GtkGrid parent;
+
+       GtkWidget *auth_method_combo;
+       GtkWidget *auth_method_label;
+       GtkWidget *key_index_combo;
+       GtkWidget *key_index_label;
+       GtkWidget *show_checkbutton_wep;
+       GtkWidget *wep_key_entry;
+       GtkWidget *wep_key_label;
+
+       NMConnection *connection;
+       gboolean secrets_only;
+       NMWepKeyType adhoc_create;
+       NMWepKeyType key_type;
+
+       char keys[4][65];
+       guint8 cur_index;
+};
+
+static void nma_ws_interface_init (NMAWsInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NMAWsWepKey, nma_ws_wep_key, GTK_TYPE_GRID,
+                         G_IMPLEMENT_INTERFACE (NMA_TYPE_WS, nma_ws_interface_init))
+
+enum {
+       PROP_0,
+       PROP_CONNECTION,
+       PROP_SECRETS_ONLY,
+       PROP_KEY_TYPE,
+       PROP_ADHOC_CREATE,
+       PROP_LAST
+};
+
+static void
+show_toggled_cb (GtkCheckButton *button, gpointer user_data)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (user_data);
+       gboolean visible;
+
+       visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       gtk_entry_set_visibility (GTK_ENTRY (self->wep_key_entry), visible);
+}
+
+static void
+key_index_combo_changed_cb (GtkWidget *combo, NMAWs *ws)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (ws);
+       GtkWidget *entry;
+       const char *key;
+       int key_index;
+
+       /* Save WEP key for old key index */
+       entry = GTK_WIDGET (self->wep_key_entry);
+       key = gtk_editable_get_text (GTK_EDITABLE (entry));
+       if (key)
+               g_strlcpy (self->keys[self->cur_index], key, sizeof (self->keys[self->cur_index]));
+       else
+               memset (self->keys[self->cur_index], 0, sizeof (self->keys[self->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), self->keys[key_index]);
+       self->cur_index = key_index;
+
+       nma_ws_changed_cb (combo, ws);
+}
+
+static gboolean
+validate (NMAWs *ws, GError **error)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (ws);
+       NMSettingSecretFlags secret_flags;
+       const char *key;
+       int i;
+
+       secret_flags = nma_utils_menu_to_secret_flags (self->wep_key_entry);
+       key = gtk_editable_get_text (GTK_EDITABLE (self->wep_key_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 (self->wep_key_entry);
+               g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("missing wep-key"));
+               return FALSE;
+       } else if (self->key_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 (self->wep_key_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 (self->wep_key_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 (self->wep_key_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 (self->key_type == NM_WEP_KEY_TYPE_PASSPHRASE) {
+               if (!*key || (strlen (key) > 64)) {
+                       widget_set_error (self->wep_key_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 (self->wep_key_entry);
+
+       return TRUE;
+}
+
+static void
+add_to_size_group (NMAWs *ws, GtkSizeGroup *group)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (ws);
+
+       gtk_size_group_add_widget (group, self->auth_method_label);
+       gtk_size_group_add_widget (group, self->wep_key_label);
+       gtk_size_group_add_widget (group, self->key_index_label);
+}
+
+static void
+fill_connection (NMAWs *ws, NMConnection *connection)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (ws);
+       NMSettingWirelessSecurity *s_wsec;
+       NMSettingSecretFlags secret_flags;
+       int auth_alg;
+       const char *key;
+       int i;
+
+       auth_alg = gtk_combo_box_get_active (GTK_COMBO_BOX (self->auth_method_combo));
+       key = gtk_editable_get_text (GTK_EDITABLE (self->wep_key_entry));
+       g_strlcpy (self->keys[self->cur_index], key, sizeof (self->keys[self->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, self->cur_index,
+                     NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, (auth_alg == 1) ? "shared" : "open",
+                     NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, self->key_type,
+                     NULL);
+
+       for (i = 0; i < 4; i++) {
+               if (strlen (self->keys[i]))
+                       nm_setting_wireless_security_set_wep_key (s_wsec, i, self->keys[i]);
+       }
+
+       /* Save WEP_KEY_FLAGS to the connection */
+       secret_flags = nma_utils_menu_to_secret_flags (self->wep_key_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 (!self->secrets_only) {
+               nma_utils_update_password_storage (self->wep_key_entry, secret_flags,
+                                                  NM_SETTING (s_wsec),
+                                                  NM_SETTING_WIRELESS_SECURITY_WEP_KEY0);
+       }
+}
+
+static void
+wep_entry_filter_cb (GtkEditable *editable,
+                     char *text,
+                     int length,
+                     int *position,
+                     gpointer data)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (data);
+
+       if (self->key_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 *ws, NMConnection *connection)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (ws);
+       NMSettingWirelessSecurity *s_wsec;
+       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 (self->keys[i], tmp, sizeof (self->keys[i]));
+       }
+
+       if (strlen (self->keys[self->cur_index])) {
+               gtk_editable_set_text (GTK_EDITABLE (self->wep_key_entry),
+                                      self->keys[self->cur_index]);
+       }
+}
+
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               g_value_set_object (value, self->connection);
+               break;
+       case PROP_SECRETS_ONLY:
+               g_value_set_boolean (value, self->secrets_only);
+               break;
+       case PROP_KEY_TYPE:
+               g_value_set_uint (value, self->key_type);
+               break;
+       case PROP_ADHOC_CREATE:
+               g_value_set_boolean (value, self->adhoc_create);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+set_property (GObject *object,
+              guint prop_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               self->connection = g_value_dup_object (value);
+               break;
+       case PROP_SECRETS_ONLY:
+               self->secrets_only = g_value_get_boolean (value);
+               break;
+       case PROP_KEY_TYPE:
+               self->key_type = g_value_get_uint (value);
+               break;
+       case PROP_ADHOC_CREATE:
+               self->adhoc_create = g_value_get_boolean (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+nma_ws_wep_key_init (NMAWsWepKey *self)
+{
+       gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+nma_ws_interface_init (NMAWsInterface *iface)
+{
+       iface->validate = validate;
+       iface->add_to_size_group = add_to_size_group;
+       iface->fill_connection = fill_connection;
+       iface->update_secrets = update_secrets;
+       iface->adhoc_compatible = TRUE;
+       iface->hotspot_compatible = TRUE;
+}
+
+static void
+constructed (GObject *object)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (object);
+       NMSettingWirelessSecurity *s_wsec = NULL;
+       NMSetting *setting = NULL;
+       guint8 default_key_idx = 0;
+       gboolean is_adhoc = self->adhoc_create;
+       gboolean is_shared_key = FALSE;
+
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       if (self->connection)
+               setting = (NMSetting *) nm_connection_get_setting_wireless_security (self->connection);
+       nma_utils_setup_password_storage (self->wep_key_entry, 0, setting,
+                                         NM_SETTING_WIRELESS_SECURITY_WEP_KEY0,
+                                         FALSE, self->secrets_only);
+
+       if (self->connection) {
+               NMSettingWireless *s_wireless;
+               const char *mode, *auth_alg;
+
+               s_wireless = nm_connection_get_setting_wireless (self->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 (self->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;
+               }
+       }
+
+       if (self->key_type == NM_WEP_KEY_TYPE_KEY)
+               gtk_entry_set_max_length (GTK_ENTRY (self->wep_key_entry), 26);
+       else if (self->key_type == NM_WEP_KEY_TYPE_PASSPHRASE)
+               gtk_entry_set_max_length (GTK_ENTRY (self->wep_key_entry), 64);
+
+       if (self->connection && s_wsec)
+               default_key_idx = nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec);
+
+       gtk_combo_box_set_active (GTK_COMBO_BOX (self->key_index_combo), default_key_idx);
+       self->cur_index = default_key_idx;
+
+       /* Key index is useless with adhoc networks */
+       if (is_adhoc || self->secrets_only) {
+               gtk_widget_hide (self->key_index_combo);
+               gtk_widget_hide (self->key_index_label);
+       }
+
+       /* Fill the key entry with the key for that index */
+       if (self->connection)
+               update_secrets (NMA_WS (self), self->connection);
+
+       gtk_combo_box_set_active (GTK_COMBO_BOX (self->auth_method_combo),
+                                 is_shared_key ? 1 : 0);
+
+       /* Don't show auth method for adhoc (which always uses open-system) or
+        * when in "simple" mode.
+        */
+       if (is_adhoc || self->secrets_only) {
+               /* Ad-Hoc connections can't use Shared Key auth */
+               if (is_adhoc)
+                       gtk_combo_box_set_active (GTK_COMBO_BOX (self->auth_method_combo), 0);
+               gtk_widget_hide (self->auth_method_combo);
+               gtk_widget_hide (self->auth_method_label);
+       }
+
+       gtk_widget_grab_focus (self->wep_key_entry);
+
+       G_OBJECT_CLASS (nma_ws_wep_key_parent_class)->constructed (object);
+}
+
+NMAWsWepKey *
+nma_ws_wep_key_new (NMConnection *connection,
+                    NMWepKeyType key_type,
+                    gboolean adhoc_create,
+                    gboolean secrets_only)
+{
+       return g_object_new (NMA_TYPE_WS_WEP_KEY,
+                            "connection", connection,
+                            "key-type", key_type,
+                            "adhoc-create", adhoc_create,
+                            "secrets-only", secrets_only,
+                            NULL);
+}
+
+static void
+dispose (GObject *object)
+{
+       NMAWsWepKey *self = NMA_WS_WEP_KEY (object);
+
+       g_clear_object (&self->connection);
+}
+
+static void
+nma_ws_wep_key_class_init (NMAWsWepKeyClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->get_property = get_property;
+       object_class->set_property = set_property;
+       object_class->constructed = constructed;
+       object_class->dispose = dispose;
+
+       g_object_class_override_property (object_class,
+                                         PROP_CONNECTION, "connection");
+
+       g_object_class_override_property (object_class,
+                                         PROP_SECRETS_ONLY, "secrets-only");
+
+       g_object_class_install_property
+               (object_class, PROP_KEY_TYPE,
+                g_param_spec_uint ("key-type", "", "",
+                                   0, G_MAXUINT, 0,
+                                     G_PARAM_READWRITE
+                                   | G_PARAM_CONSTRUCT
+                                   | G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property
+               (object_class, PROP_ADHOC_CREATE,
+               g_param_spec_boolean ("adhoc-create", "", "",
+                                     FALSE,
+                                       G_PARAM_READWRITE
+                                     | G_PARAM_CONSTRUCT
+                                     | G_PARAM_STATIC_STRINGS));
+
+        gtk_widget_class_set_template_from_resource (widget_class,
+                                                     "/org/gnome/libnma/nma-ws-wep-key.ui");
+
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWepKey, auth_method_combo);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWepKey, auth_method_label);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWepKey, key_index_combo);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWepKey, key_index_label);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWepKey, show_checkbutton_wep);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWepKey, wep_key_entry);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWepKey, wep_key_label);
+
+       gtk_widget_class_bind_template_callback (widget_class, key_index_combo_changed_cb);
+       gtk_widget_class_bind_template_callback (widget_class, nma_ws_changed_cb);
+       gtk_widget_class_bind_template_callback (widget_class, show_toggled_cb);
+       gtk_widget_class_bind_template_callback (widget_class, wep_entry_filter_cb);
+}
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..308f975c
--- /dev/null
+++ b/src/nma-ws/nma-ws-wep-key.h
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_WEP_KEY_H
+#define NMA_WS_WEP_KEY_H
+
+#include "nma-version.h"
+
+G_BEGIN_DECLS
+
+typedef struct _NMAWsWepKey NMAWsWepKey;
+
+#define NMA_TYPE_WS_WEP_KEY            (nma_ws_wep_key_get_type ())
+#define NMA_WS_WEP_KEY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMA_TYPE_WS_WEP_KEY, NMAWsWepKey))
+#define NMA_WS_WEP_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMA_TYPE_WS_WEP_KEY, 
NMAWsWepKeyClass))
+#define NMA_IS_WS_WEP_KEY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMA_TYPE_WS_WEP_KEY))
+#define NMA_IS_WS_WEP_KEY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMA_TYPE_WS_WEP_KEY))
+#define NMA_WS_WEP_KEY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMA_TYPE_WS_WEP_KEY, 
NMAWsWepKeyClass))
+
+NMA_AVAILABLE_IN_1_8_28
+GType nma_ws_wep_key_get_type (void);
+
+NMA_AVAILABLE_IN_1_8_28
+NMAWsWepKey *nma_ws_wep_key_new (NMConnection *connection,
+                                 NMWepKeyType type,
+                                 gboolean adhoc_create,
+                                 gboolean secrets_only);
+
+G_END_DECLS
+
+#endif /* NMA_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..002de229
--- /dev/null
+++ b/src/nma-ws/nma-ws-wep-key.ui
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <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>
+  <template class="NMAWsWepKey" parent="GtkGrid">
+    <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>
+        <property name="width_chars">28</property>
+        <signal name="changed" handler="nma_ws_changed_cb" swapped="no"/>
+        <signal name="insert-text" handler="wep_entry_filter_cb" swapped="no"/>
+      </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>
+        <signal name="toggled" handler="show_toggled_cb" swapped="no"/>
+      </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>
+        <signal name="changed" handler="nma_ws_changed_cb" swapped="no"/>
+      </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>
+        <signal name="changed" handler="key_index_combo_changed_cb" swapped="no"/>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="top_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <placeholder/>
+    </child>
+  </template>
+</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..f8c8daf0
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-eap.c
@@ -0,0 +1,70 @@
+// 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 "nma-ws.h"
+#include "nma-ws-private.h"
+#include "nma-ws-802-1x.h"
+#include "nma-ws-802-1x-private.h"
+#include "nma-ws-wpa-eap.h"
+
+typedef struct {
+       NMAWs8021xClass parent;
+} NMAWsWpaEapClass;
+
+struct _NMAWsWpaEap {
+       NMAWs8021x parent;
+};
+
+static void nma_ws_interface_init (NMAWsInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NMAWsWpaEap, nma_ws_wpa_eap, NMA_TYPE_WS_802_1X,
+                         G_IMPLEMENT_INTERFACE (NMA_TYPE_WS, nma_ws_interface_init))
+
+static void
+fill_connection (NMAWs *ws, NMConnection *connection)
+{
+       NMSettingWirelessSecurity *s_wireless_sec;
+
+       nma_ws_802_1x_fill_connection (ws, connection);
+
+       s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
+       g_return_if_fail (s_wireless_sec);
+
+       g_object_set (s_wireless_sec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap", NULL);
+}
+
+static void
+nma_ws_wpa_eap_init (NMAWsWpaEap *self)
+{
+}
+
+static void
+nma_ws_interface_init (NMAWsInterface *iface)
+{
+       iface->fill_connection = fill_connection;
+}
+
+NMAWsWpaEap *
+nma_ws_wpa_eap_new (NMConnection *connection,
+                    gboolean is_editor,
+                    gboolean secrets_only,
+                    const char *const*secrets_hints)
+{
+       return g_object_new (NMA_TYPE_WS_WPA_EAP,
+                            "connection", connection,
+                            "secrets-only", secrets_only,
+                            "is-editor", is_editor,
+                            "secrets-hints", secrets_hints,
+                            NULL);
+}
+
+static void
+nma_ws_wpa_eap_class_init (NMAWsWpaEapClass *klass)
+{
+}
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..e53df74b
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-eap.h
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_WPA_EAP_H
+#define NMA_WS_WPA_EAP_H
+
+#include "nma-version.h"
+
+G_BEGIN_DECLS
+
+typedef struct _NMAWsWpaEap NMAWsWpaEap;
+
+#define NMA_TYPE_WS_WPA_EAP            (nma_ws_wpa_eap_get_type ())
+#define NMA_WS_WPA_EAP(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMA_TYPE_WS_SAE, NMAWsWpaEap))
+#define NMA_WS_WPA_EAP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMA_TYPE_WS_SAE, NMAWsWpaEapClass))
+#define NMA_IS_WS_WPA_EAP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMA_TYPE_WS_SAE))
+#define NMA_IS_WS_WPA_EAP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMA_TYPE_WS_SAE))
+#define NMA_WS_WPA_EAP_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMA_TYPE_WS_SAE, NMAWsWpaEapClass))
+
+NMA_AVAILABLE_IN_1_8_28
+GType nma_ws_wpa_eap_get_type (void);
+
+NMA_AVAILABLE_IN_1_8_28
+NMAWsWpaEap *nma_ws_wpa_eap_new (NMConnection *connection,
+                                 gboolean is_editor,
+                                 gboolean secrets_only,
+                                 const char *const*secrets_hints);
+
+G_END_DECLS
+
+#endif /* NMA_WS_WPA_EAP_H */
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..a161243f
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-psk.c
@@ -0,0 +1,303 @@
+// 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 "nma-ws-private.h"
+#include "nma-ws-wpa-psk.h"
+#include "nma-ws-helpers.h"
+#include "nma-ui-utils.h"
+#include "utils.h"
+
+#define WPA_PMK_LEN 32
+
+typedef struct {
+       GtkGridClass parent;
+} NMAWsWpaPskClass;
+
+struct _NMAWsWpaPsk {
+       GtkGrid parent;
+
+       GtkWidget *wpa_psk_entry;
+       GtkWidget *wpa_psk_label;
+       GtkWidget *wpa_psk_type_combo;
+       GtkWidget *wpa_psk_type_label;
+       GtkWidget *show_checkbutton_wpa;
+
+       NMConnection *connection;
+       gboolean secrets_only;
+};
+
+static void nma_ws_interface_init (NMAWsInterface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (NMAWsWpaPsk, nma_ws_wpa_psk, GTK_TYPE_GRID,
+                         G_IMPLEMENT_INTERFACE (NMA_TYPE_WS, nma_ws_interface_init))
+
+enum {
+       PROP_0,
+       PROP_CONNECTION,
+       PROP_SECRETS_ONLY,
+       PROP_LAST
+};
+
+static void
+show_toggled_cb (GtkCheckButton *button, gpointer user_data)
+{
+       NMAWsWpaPsk *self = NMA_WS_WPA_PSK (user_data);
+       gboolean visible;
+
+       visible = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+       gtk_entry_set_visibility (GTK_ENTRY (self->wpa_psk_entry), visible);
+}
+
+static gboolean
+validate (NMAWs *ws, GError **error)
+{
+       NMAWsWpaPsk *self = NMA_WS_WPA_PSK (ws);
+       NMSettingSecretFlags secret_flags;
+       const char *key;
+       gsize len;
+       int i;
+
+       secret_flags = nma_utils_menu_to_secret_flags (self->wpa_psk_entry);
+       key = gtk_editable_get_text (GTK_EDITABLE (self->wpa_psk_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 (self->wpa_psk_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 (self->wpa_psk_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 (self->wpa_psk_entry);
+
+       /* passphrase can be between 8 and 63 characters inclusive */
+
+       return TRUE;
+}
+
+static void
+add_to_size_group (NMAWs *ws, GtkSizeGroup *group)
+{
+       NMAWsWpaPsk *self = NMA_WS_WPA_PSK (ws);
+
+       gtk_size_group_add_widget (group, self->wpa_psk_type_label);
+       gtk_size_group_add_widget (group, self->wpa_psk_label);
+}
+
+static void
+fill_connection (NMAWs *ws, NMConnection *connection)
+{
+       NMAWsWpaPsk *self = NMA_WS_WPA_PSK (ws);
+       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_return_if_fail (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);
+
+       key = gtk_editable_get_text (GTK_EDITABLE (self->wpa_psk_entry));
+       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 (self->wpa_psk_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 (!self->secrets_only) {
+               nma_utils_update_password_storage (self->wpa_psk_entry, secret_flags,
+                                                  NM_SETTING (s_wireless_sec),
+                                                  NM_SETTING_WIRELESS_SECURITY_PSK);
+       }
+
+       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 *ws, NMConnection *connection)
+{
+       NMAWsWpaPsk *self = NMA_WS_WPA_PSK (ws);
+
+       nma_ws_helper_fill_secret_entry (connection,
+                                        GTK_EDITABLE (self->wpa_psk_entry),
+                                        NM_TYPE_SETTING_WIRELESS_SECURITY,
+                                        (HelperSecretFunc) nm_setting_wireless_security_get_psk);
+}
+
+static void
+get_property (GObject *object,
+              guint prop_id,
+              GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWsWpaPsk *self = NMA_WS_WPA_PSK (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               g_value_set_object (value, self->connection);
+               break;
+       case PROP_SECRETS_ONLY:
+               g_value_set_boolean (value, self->secrets_only);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+set_property (GObject *object,
+              guint prop_id,
+              const GValue *value,
+              GParamSpec *pspec)
+{
+       NMAWsWpaPsk *self = NMA_WS_WPA_PSK (object);
+
+       switch (prop_id) {
+       case PROP_CONNECTION:
+               self->connection = g_value_dup_object (value);
+               break;
+       case PROP_SECRETS_ONLY:
+               self->secrets_only = g_value_get_boolean (value);
+               break;
+       default:
+               G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+               break;
+       }
+}
+
+static void
+nma_ws_wpa_psk_init (NMAWsWpaPsk *self)
+{
+       gtk_widget_init_template (GTK_WIDGET (self));
+}
+
+static void
+nma_ws_interface_init (NMAWsInterface *iface)
+{
+       iface->validate = validate;
+       iface->add_to_size_group = add_to_size_group;
+       iface->fill_connection = fill_connection;
+       iface->update_secrets = update_secrets;
+       iface->adhoc_compatible = TRUE;
+       iface->hotspot_compatible = TRUE;
+}
+
+static void
+constructed (GObject *object)
+{
+       NMAWsWpaPsk *self = NMA_WS_WPA_PSK (object);
+       NMSetting *setting = NULL;
+
+       /* Create password-storage popup menu for password entry under entry's secondary icon */
+       if (self->connection)
+               setting = (NMSetting *) nm_connection_get_setting_wireless_security (self->connection);
+       nma_utils_setup_password_storage (self->wpa_psk_entry, 0, setting, NM_SETTING_WIRELESS_SECURITY_PSK,
+                                         FALSE, self->secrets_only);
+
+       /* Fill secrets, if any */
+       if (self->connection)
+               update_secrets (NMA_WS (self), self->connection);
+
+       gtk_widget_grab_focus (self->wpa_psk_entry);
+
+       /* Hide WPA/RSN for now since this can be autodetected by NM and the
+        * supplicant when connecting to the AP.
+        */
+       gtk_widget_hide (self->wpa_psk_type_combo);
+       gtk_widget_hide (self->wpa_psk_type_label);
+
+       G_OBJECT_CLASS (nma_ws_wpa_psk_parent_class)->constructed (object);
+}
+
+NMAWsWpaPsk *
+nma_ws_wpa_psk_new (NMConnection *connection, gboolean secrets_only)
+{
+       return g_object_new (NMA_TYPE_WS_WPA_PSK,
+                            "connection", connection,
+                            "secrets-only", secrets_only,
+                            NULL);
+}
+
+static void
+dispose (GObject *object)
+{
+       NMAWsWpaPsk *self = NMA_WS_WPA_PSK (object);
+
+       g_clear_object (&self->connection);
+}
+
+static void
+nma_ws_wpa_psk_class_init (NMAWsWpaPskClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+       object_class->get_property = get_property;
+       object_class->set_property = set_property;
+       object_class->constructed = constructed;
+       object_class->dispose = dispose;
+
+       g_object_class_override_property (object_class,
+                                         PROP_CONNECTION, "connection");
+
+       g_object_class_override_property (object_class,
+                                         PROP_SECRETS_ONLY, "secrets-only");
+
+        gtk_widget_class_set_template_from_resource (widget_class,
+                                                     "/org/gnome/libnma/nma-ws-wpa-psk.ui");
+
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWpaPsk, wpa_psk_entry);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWpaPsk, wpa_psk_label);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWpaPsk, wpa_psk_type_combo);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWpaPsk, wpa_psk_type_label);
+       gtk_widget_class_bind_template_child (widget_class, NMAWsWpaPsk, show_checkbutton_wpa);
+
+       gtk_widget_class_bind_template_callback (widget_class, nma_ws_changed_cb);
+       gtk_widget_class_bind_template_callback (widget_class, show_toggled_cb);
+}
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..93e0b1ac
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-psk.h
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Dan Williams <dcbw redhat com>
+ *
+ * Copyright 2007 - 2019 Red Hat, Inc.
+ */
+
+#ifndef NMA_WS_WPA_PSK_H
+#define NMA_WS_WPA_PSK_H
+
+#include "nma-version.h"
+
+G_BEGIN_DECLS
+
+typedef struct _NMAWsWpaPsk NMAWsWpaPsk;
+
+#define NMA_TYPE_WS_WPA_PSK            (nma_ws_wpa_psk_get_type ())
+#define NMA_WS_WPA_PSK(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMA_TYPE_WS_WPA_PSK, NMAWsWpaPsk))
+#define NMA_WS_WPA_PSK_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), NMA_TYPE_WS_WPA_PSK, 
NMAWsWpaPskClass))
+#define NMA_IS_WS_WPA_PSK(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMA_TYPE_WS_WPA_PSK))
+#define NMA_IS_WS_WPA_PSK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NMA_TYPE_WS_WPA_PSK))
+#define NMA_WS_WPA_PSK_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), NMA_TYPE_WS_WPA_PSK, 
NMAWsWpaPskClass))
+
+NMA_AVAILABLE_IN_1_8_28
+GType nma_ws_wpa_psk_get_type (void);
+
+NMA_AVAILABLE_IN_1_8_28
+NMAWsWpaPsk *nma_ws_wpa_psk_new (NMConnection *connection, gboolean secrets_only);
+
+G_END_DECLS
+
+#endif /* NMA_WS_WPA_PSK_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..7ee3ae49
--- /dev/null
+++ b/src/nma-ws/nma-ws-wpa-psk.ui
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface domain="libnma">
+  <requires lib="gtk+" version="3.10"/>
+  <template class="NMAWsWpaPsk" parent="GtkGrid">
+    <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>
+        <signal name="changed" handler="nma_ws_changed_cb" swapped="no"/>
+      </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>
+        <signal name="toggled" handler="show_toggled_cb" swapped="no"/>
+      </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>
+  </template>
+</interface>
diff --git a/src/nma-ws/nma-ws.c b/src/nma-ws/nma-ws.c
new file mode 100644
index 00000000..1861f822
--- /dev/null
+++ b/src/nma-ws/nma-ws.c
@@ -0,0 +1,141 @@
+// 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-ws-private.h"
+#include "nma-eap.h"
+#include "utils.h"
+
+G_DEFINE_INTERFACE (NMAWs, nma_ws, G_TYPE_OBJECT)
+
+void
+nma_ws_changed_cb (GtkWidget *ignored, gpointer user_data)
+{
+       g_signal_emit_by_name (user_data, "ws-changed");
+}
+
+gboolean
+nma_ws_validate (NMAWs *self, GError **error)
+{
+       NMAWsInterface *iface;
+       gboolean result;
+
+       g_return_val_if_fail (self != NULL, FALSE);
+       g_return_val_if_fail (!error || !*error, FALSE);
+
+       iface = NMA_WS_GET_INTERFACE (self);
+       g_return_val_if_fail (iface->validate, FALSE);
+       result = (*(iface->validate)) (self, 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 *self, GtkSizeGroup *group)
+{
+       NMAWsInterface *iface;
+
+       g_return_if_fail (self != NULL);
+       g_return_if_fail (group != NULL);
+
+       iface = NMA_WS_GET_INTERFACE (self);
+       g_return_if_fail (iface->add_to_size_group);
+       return (*(iface->add_to_size_group)) (self, group);
+}
+
+void
+nma_ws_fill_connection (NMAWs *self,
+                        NMConnection *connection)
+{
+       NMAWsInterface *iface;
+
+       g_return_if_fail (self != NULL);
+       g_return_if_fail (connection != NULL);
+
+       iface = NMA_WS_GET_INTERFACE (self);
+       g_return_if_fail (iface->fill_connection);
+       return (*(iface->fill_connection)) (self, connection);
+}
+
+void
+nma_ws_update_secrets (NMAWs *self, NMConnection *connection)
+{
+       NMAWsInterface *iface;
+
+       g_return_if_fail (self != NULL);
+       g_return_if_fail (connection != NULL);
+
+       iface = NMA_WS_GET_INTERFACE (self);
+       if (iface->update_secrets)
+               iface->update_secrets (self, connection);
+}
+
+void
+nma_ws_default_init (NMAWsInterface *iface)
+{
+       GType iface_type = G_TYPE_FROM_INTERFACE (iface);
+
+       g_signal_new ("ws-changed",
+                     iface_type,
+                     G_SIGNAL_RUN_FIRST,
+                     0, NULL, NULL,
+                     g_cclosure_marshal_VOID__VOID,
+                     G_TYPE_NONE, 0);
+
+       iface->adhoc_compatible = TRUE;
+       iface->hotspot_compatible = TRUE;
+
+       g_object_interface_install_property (iface,
+               g_param_spec_object ("connection", "", "",
+                                    NM_TYPE_CONNECTION,
+                                      G_PARAM_READWRITE
+                                    | G_PARAM_CONSTRUCT
+                                    | G_PARAM_STATIC_STRINGS));
+
+       g_object_interface_install_property (iface,
+               g_param_spec_boolean ("secrets-only", "", "",
+                                     FALSE,
+                                       G_PARAM_READWRITE
+                                     | G_PARAM_CONSTRUCT
+                                     | G_PARAM_STATIC_STRINGS));
+}
+
+gboolean
+nma_ws_adhoc_compatible (NMAWs *self)
+{
+       g_return_val_if_fail (self != NULL, FALSE);
+
+       return NMA_WS_GET_INTERFACE (self)->adhoc_compatible;
+}
+
+gboolean
+nma_ws_hotspot_compatible (NMAWs *self)
+{
+       g_return_val_if_fail (self != NULL, FALSE);
+
+       return NMA_WS_GET_INTERFACE (self)->hotspot_compatible;
+}
+
+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_return_if_fail (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);
+}
diff --git a/src/nma-ws/nma-ws.h b/src/nma-ws/nma-ws.h
new file mode 100644
index 00000000..bbea4ded
--- /dev/null
+++ b/src/nma-ws/nma-ws.h
@@ -0,0 +1,56 @@
+// 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
+
+#include "nma-version.h"
+
+G_BEGIN_DECLS
+
+typedef struct _NMAWs NMAWs;
+
+#define NMA_TYPE_WS                (nma_ws_get_type ())
+#define NMA_WS(obj)                (G_TYPE_CHECK_INSTANCE_CAST ((obj), NMA_TYPE_WS, NMAWs))
+#define NMA_IS_WS(obj)             (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NMA_TYPE_WS))
+#define NMA_WS_GET_INTERFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NMA_TYPE_WS, NMAWsInterface))
+
+NMA_AVAILABLE_IN_1_8_28
+GType nma_ws_get_type (void);
+
+NMA_AVAILABLE_IN_1_8_28
+gboolean nma_ws_validate (NMAWs *self, GError **error);
+
+NMA_AVAILABLE_IN_1_8_28
+void nma_ws_add_to_size_group (NMAWs *self,
+                               GtkSizeGroup *group);
+
+NMA_AVAILABLE_IN_1_8_28
+void nma_ws_fill_connection (NMAWs *self,
+                             NMConnection *connection);
+
+NMA_AVAILABLE_IN_1_8_28
+void nma_ws_update_secrets (NMAWs *self,
+                            NMConnection *connection);
+
+NMA_AVAILABLE_IN_1_8_28
+gboolean nma_ws_adhoc_compatible (NMAWs *self);
+
+NMA_AVAILABLE_IN_1_8_28
+gboolean nma_ws_hotspot_compatible (NMAWs *self);
+
+G_END_DECLS
+
+#include "nma-ws-802-1x.h"
+#include "nma-ws-dynamic-wep.h"
+#include "nma-ws-leap.h"
+#include "nma-ws-sae.h"
+#include "nma-ws-wep-key.h"
+#include "nma-ws-wpa-eap.h"
+#include "nma-ws-wpa-psk.h"
+
+#endif /* NMA_WS_H */
diff --git a/src/nma.gresource.xml b/src/nma.gresource.xml
index cfe41a7f..5c75f112 100644
--- a/src/nma.gresource.xml
+++ b/src/nma.gresource.xml
@@ -7,5 +7,16 @@
                <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-802-1x.ui">nma-ws/nma-ws-802-1x.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-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>
diff --git a/src/wireless-security/ws-leap.ui b/src/wireless-security/ws-leap.ui
index df9ed78d..a3ff0a9a 100644
--- a/src/wireless-security/ws-leap.ui
+++ b/src/wireless-security/ws-leap.ui
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.20.0 -->
+<!-- Generated with glade 3.22.1 -->
 <interface domain="libnma">
   <requires lib="gtk+" version="3.10"/>
   <object class="GtkNotebook" id="leap_notebook">


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