[evolution-data-server] Move authentication of backends back to the client



commit 884fb8d872787d9c9e8132d4cfca47f275d9da3e
Author: Milan Crha <mcrha redhat com>
Date:   Mon Feb 2 14:44:05 2015 +0100

    Move authentication of backends back to the client
    
    Since this change the client is responsible to provide credentials
    to use to authenticate backends (through ESource-s, to be more precise),
    unless the credentials are already saved.

 Makefile.am                                        |    5 +
 addressbook/backends/file/e-book-backend-file.c    |    3 +
 .../backends/google/e-book-backend-google.c        |  163 ++-
 addressbook/backends/ldap/e-book-backend-ldap.c    |  120 +-
 .../backends/webdav/e-book-backend-webdav.c        |  180 ++-
 addressbook/libebook/e-book-client.c               |  101 ++-
 addressbook/libebook/e-book-client.h               |    4 +
 addressbook/libedata-book/e-book-backend.c         |   19 -
 addressbook/libedata-book/e-data-book.c            |   67 +-
 calendar/backends/caldav/e-cal-backend-caldav.c    |  253 ++-
 .../backends/contacts/e-cal-backend-contacts.c     |    6 +-
 calendar/backends/file/e-cal-backend-file.c        |    4 +
 calendar/backends/gtasks/e-cal-backend-gtasks.c    |    8 +-
 calendar/backends/http/e-cal-backend-http.c        |  214 ++-
 calendar/libecal/e-cal-client.c                    |   93 +
 calendar/libecal/e-cal-client.h                    |    2 +
 calendar/libedata-cal/e-cal-backend.c              |   19 -
 calendar/libedata-cal/e-data-cal.c                 |   66 +-
 configure.ac                                       |   36 +-
 examples/cursor/cursor-data.c                      |    2 +-
 libebackend/Makefile.am                            |   12 +-
 libebackend/e-authentication-mediator.c            | 1290 --------------
 libebackend/e-authentication-mediator.h            |  115 --
 libebackend/e-authentication-session.c             | 1794 --------------------
 libebackend/e-authentication-session.h             |  232 ---
 libebackend/e-backend-factory.c                    |    3 +-
 libebackend/e-backend-factory.h                    |    2 +-
 libebackend/e-backend.c                            |  554 +++++--
 libebackend/e-backend.h                            |   49 +-
 libebackend/e-collection-backend.c                 |  111 +-
 libebackend/e-collection-backend.h                 |    3 +
 libebackend/e-data-factory.c                       |    3 +-
 libebackend/e-dbus-server.c                        |    2 -
 .../e-server-side-source-credentials-provider.c    |   92 +
 .../e-server-side-source-credentials-provider.h    |   79 +
 libebackend/e-server-side-source.c                 |  571 +++++--
 libebackend/e-server-side-source.h                 |   12 -
 libebackend/e-soup-ssl-trust.c                     |  104 +-
 libebackend/e-soup-ssl-trust.h                     |    4 +-
 libebackend/e-source-registry-server.c             |  756 +--------
 libebackend/e-source-registry-server.h             |   24 +-
 libebackend/e-subprocess-factory.c                 |    4 +-
 libebackend/libebackend.h                          |    5 -
 libedataserver/Makefile.am                         |   15 +-
 libedataserver/e-client.c                          |  290 ++++
 libedataserver/e-client.h                          |   30 +
 libedataserver/e-data-server-util.c                |   99 ++-
 libedataserver/e-data-server-util.h                |   23 +
 {libebackend => libedataserver}/e-extensible.c     |   15 +-
 {libebackend => libedataserver}/e-extensible.h     |    4 +-
 {libebackend => libedataserver}/e-extension.c      |    8 +-
 {libebackend => libedataserver}/e-extension.h      |    6 +-
 {libebackend => libedataserver}/e-module.c         |   55 +-
 {libebackend => libedataserver}/e-module.h         |   21 +-
 libedataserver/e-source-authentication.c           |  121 ++-
 libedataserver/e-source-authentication.h           |    7 +
 libedataserver/e-source-authenticator.c            |  528 ------
 libedataserver/e-source-authenticator.h            |  115 --
 .../e-source-credentials-provider-impl-password.c  |  144 ++
 .../e-source-credentials-provider-impl-password.h  |   75 +
 .../e-source-credentials-provider-impl.c           |  319 ++++
 .../e-source-credentials-provider-impl.h           |  128 ++
 libedataserver/e-source-credentials-provider.c     | 1030 +++++++++++
 libedataserver/e-source-credentials-provider.h     |  150 ++
 libedataserver/e-source-enums.h                    |   72 +-
 libedataserver/e-source-registry.c                 |  674 ++------
 libedataserver/e-source-registry.h                 |   23 +-
 libedataserver/e-source-webdav.c                   |  385 +----
 libedataserver/e-source-webdav.h                   |   30 +-
 libedataserver/e-source.c                          | 1003 +++++++++++-
 libedataserver/e-source.h                          |  129 ++-
 libedataserver/libedataserver-private.h            |   11 +-
 libedataserver/libedataserver.h                    |    6 +
 libedataserver/libedataserver.pc.in                |    3 +
 libedataserverui/Makefile.am                       |   77 +
 .../e-credentials-prompter-impl-password.c         |  561 ++++++
 .../e-credentials-prompter-impl-password.h         |   78 +
 libedataserverui/e-credentials-prompter-impl.c     |  232 +++
 libedataserverui/e-credentials-prompter-impl.h     |  115 ++
 libedataserverui/e-credentials-prompter.c          | 1763 +++++++++++++++++++
 libedataserverui/e-credentials-prompter.h          |  189 ++
 libedataserverui/e-trust-prompt.c                  |  672 ++++++++
 libedataserverui/e-trust-prompt.h                  |   59 +
 libedataserverui/libedataserverui.h                |   30 +
 libedataserverui/libedataserverui.pc.in            |   18 +
 modules/gnome-online-accounts/Makefile.am          |   36 +-
 .../gnome-online-accounts/e-goa-password-based.c   |  193 +--
 .../gnome-online-accounts/e-goa-password-based.h   |    6 +-
 .../gnome-online-accounts/module-credentials-goa.c |   37 +
 .../module-gnome-online-accounts.c                 |    9 -
 modules/owncloud-backend/module-owncloud-backend.c |   53 +-
 modules/owncloud-backend/owncloud-utils.c          |  192 +--
 modules/owncloud-backend/owncloud-utils.h          |    7 +-
 modules/ubuntu-online-accounts/Makefile.am         |   38 +-
 .../e-signon-session-password.c                    |  375 ++---
 .../e-signon-session-password.h                    |    6 +-
 .../module-credentials-uoa.c                       |   37 +
 .../module-ubuntu-online-accounts.c                |    7 -
 po/POTFILES.in                                     |    8 +-
 .../org.gnome.evolution.dataserver.AddressBook.xml |    4 +
 .../org.gnome.evolution.dataserver.Calendar.xml    |    4 +
 private/org.gnome.evolution.dataserver.Source.xml  |   99 +-
 ...rg.gnome.evolution.dataserver.SourceManager.xml |   34 -
 tests/book-migration/setup-migration-test.c        |    2 +-
 tests/libebook/client/test-book-client-self.c      |    2 +-
 .../client/test-book-client-view-operations.c      |    8 +-
 tests/test-server-utils/e-test-server-utils.c      |   12 +-
 107 files changed, 10348 insertions(+), 7320 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 6f219eb..26495b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,12 +9,17 @@ DISTCHECK_CONFIGURE_FLAGS = \
        --disable-examples \
        $(NULL)
 
+if HAVE_GTK
+EDSUI_SUBDIR=libedataserverui
+endif
+
 SUBDIRS = \
        camel \
        data \
        private \
        libedataserver \
        libebackend \
+       $(EDSUI_SUBDIR) \
        addressbook \
        calendar \
        modules \
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c
index 8f8f085..b0dbe79 100644
--- a/addressbook/backends/file/e-book-backend-file.c
+++ b/addressbook/backends/file/e-book-backend-file.c
@@ -1140,6 +1140,9 @@ book_backend_file_open_sync (EBookBackend *backend,
 
        source = e_backend_get_source (E_BACKEND (backend));
 
+       /* Local source is always connected. */
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+
        g_type_ensure (E_TYPE_SOURCE_REVISION_GUARDS);
        guards = e_source_get_extension (source, E_SOURCE_EXTENSION_REVISION_GUARDS);
 
diff --git a/addressbook/backends/google/e-book-backend-google.c 
b/addressbook/backends/google/e-book-backend-google.c
index 19d1ac7..7f4d29b 100644
--- a/addressbook/backends/google/e-book-backend-google.c
+++ b/addressbook/backends/google/e-book-backend-google.c
@@ -44,17 +44,7 @@
 #define GDATA_CHECK_VERSION(major,minor,micro) 0
 #endif
 
-/* Forward Declarations */
-static void    e_book_backend_google_source_authenticator_init
-                               (ESourceAuthenticatorInterface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (
-       EBookBackendGoogle,
-       e_book_backend_google,
-       E_TYPE_BOOK_BACKEND,
-       G_IMPLEMENT_INTERFACE (
-               E_TYPE_SOURCE_AUTHENTICATOR,
-               e_book_backend_google_source_authenticator_init))
+G_DEFINE_TYPE (EBookBackendGoogle, e_book_backend_google, E_TYPE_BOOK_BACKEND)
 
 struct _EBookBackendGooglePrivate {
        EBookBackendCache *cache;
@@ -1209,9 +1199,9 @@ fallback_set_proxy_uri (EBookBackend *backend)
 #endif
 
 static gboolean
-request_authorization (EBookBackend *backend,
-                       GCancellable *cancellable,
-                       GError **error)
+connect_without_password (EBookBackend *backend,
+                         GCancellable *cancellable,
+                         GError **error)
 {
        EBookBackendGooglePrivate *priv;
 
@@ -1277,10 +1267,7 @@ request_authorization (EBookBackend *backend,
                return TRUE;
 
        /* Otherwise it's up to us to obtain a login secret. */
-       return e_backend_authenticate_sync (
-               E_BACKEND (backend),
-               E_SOURCE_AUTHENTICATOR (backend),
-               cancellable, error);
+       return FALSE;
 }
 
 typedef enum {
@@ -1421,6 +1408,7 @@ e_book_backend_google_notify_online_cb (EBookBackend *backend,
                                         GParamSpec *pspec)
 {
        EBookBackendGooglePrivate *priv;
+       ESource *source;
        gboolean is_online;
 
        priv = E_BOOK_BACKEND_GOOGLE_GET_PRIVATE (backend);
@@ -1428,11 +1416,22 @@ e_book_backend_google_notify_online_cb (EBookBackend *backend,
        g_debug (G_STRFUNC);
 
        is_online = e_backend_get_online (E_BACKEND (backend));
+       source = e_backend_get_source (E_BACKEND (backend));
 
        if (is_online && e_book_backend_is_opened (backend)) {
-               request_authorization (backend, NULL, NULL);
-               if (backend_is_authorized (backend))
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
+
+               if (connect_without_password (backend, NULL, NULL)) {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+
                        e_book_backend_set_writable (backend, TRUE);
+                       cache_refresh_if_needed (backend);
+               } else {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+
+                       e_backend_schedule_credentials_required (E_BACKEND (backend), 
E_SOURCE_CREDENTIALS_REASON_REQUIRED,
+                               NULL, 0, NULL, NULL, G_STRFUNC);
+               }
        } else {
                /* Going offline, so cancel all running operations */
                google_cancel_all_operations (backend);
@@ -1443,6 +1442,9 @@ e_book_backend_google_notify_online_cb (EBookBackend *backend,
                 * as writeable again once the user's authenticated again. */
                e_book_backend_set_writable (backend, FALSE);
 
+               if (e_source_get_connection_status (source) != E_SOURCE_CONNECTION_STATUS_DISCONNECTED)
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+
                /* We can free our service. */
                g_clear_object (&priv->service);
        }
@@ -1711,19 +1713,52 @@ book_backend_google_open_sync (EBookBackend *backend,
        e_book_backend_set_writable (backend, FALSE);
 
        if (is_online) {
-               success = request_authorization (backend, cancellable, error);
+               ESource *source = e_backend_get_source (E_BACKEND (backend));
+
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
+
+               success = connect_without_password (backend, cancellable, error);
                if (success) {
+                       GError *local_error = NULL;
+
                        /* Refresh the authorizer.  This may block. */
                        success = gdata_authorizer_refresh_authorization (
-                               priv->authorizer, cancellable, error);
+                               priv->authorizer, cancellable, &local_error);
+
+                       if (success) {
+                               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+                       } else {
+                               GError *local_error2 = NULL;
+
+                               e_source_set_connection_status (source, 
E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+
+                               if (local_error && !e_backend_credentials_required_sync (E_BACKEND (backend), 
E_SOURCE_CREDENTIALS_REASON_ERROR,
+                                       NULL, 0, local_error, cancellable, &local_error2)) {
+                                       g_warning ("%s: Failed to call credentials required: %s", G_STRFUNC, 
local_error2 ? local_error2->message : "Unknown error");
+                               }
+
+                               g_clear_error (&local_error2);
+
+                               if (local_error)
+                                       g_propagate_error (error, local_error);
+                       }
+               } else {
+                       GError *local_error = NULL;
+
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+
+                       if (!e_backend_credentials_required_sync (E_BACKEND (backend), 
E_SOURCE_CREDENTIALS_REASON_REQUIRED,
+                               NULL, 0, NULL, cancellable, &local_error)) {
+                               g_warning ("%s: Failed to call credentials required: %s", G_STRFUNC, 
local_error ? local_error->message : "Unknown error");
+                       }
+
+                       g_clear_error (&local_error);
                }
        }
 
-       if (!is_online || backend_is_authorized (backend)) {
-               if (is_online) {
-                       e_book_backend_set_writable (backend, TRUE);
-                       cache_refresh_if_needed (backend);
-               }
+       if (is_online && backend_is_authorized (backend)) {
+               e_book_backend_set_writable (backend, TRUE);
+               cache_refresh_if_needed (backend);
        }
 
        return success;
@@ -2281,16 +2316,18 @@ book_backend_google_refresh_sync (EBookBackend *backend,
 }
 
 static ESourceAuthenticationResult
-book_backend_google_try_password_sync (ESourceAuthenticator *authenticator,
-                                       const GString *password,
-                                       GCancellable *cancellable,
-                                       GError **error)
+book_backend_google_authenticate_sync (EBackend *backend,
+                                      const ENamedParameters *credentials,
+                                      gchar **out_certificate_pem,
+                                      GTlsCertificateFlags *out_certificate_errors,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
        EBookBackendGooglePrivate *priv;
        ESourceAuthentication *auth_extension;
        ESourceAuthenticationResult result;
        ESource *source;
-       const gchar *extension_name;
+       const gchar *username;
        gchar *user;
        GError *local_error = NULL;
 
@@ -2298,24 +2335,34 @@ book_backend_google_try_password_sync (ESourceAuthenticator *authenticator,
 
        /* We should not have gotten here if we're offline. */
        g_return_val_if_fail (
-               e_backend_get_online (E_BACKEND (authenticator)),
+               e_backend_get_online (E_BACKEND (backend)),
                E_SOURCE_AUTHENTICATION_ERROR);
 
        /* Nor should we have gotten here if we're already authorized. */
        g_return_val_if_fail (
-               !backend_is_authorized (E_BOOK_BACKEND (authenticator)),
+               !backend_is_authorized (E_BOOK_BACKEND (backend)),
                E_SOURCE_AUTHENTICATION_ERROR);
 
-       priv = E_BOOK_BACKEND_GOOGLE (authenticator)->priv;
+       priv = E_BOOK_BACKEND_GOOGLE (backend)->priv;
 
-       source = e_backend_get_source (E_BACKEND (authenticator));
-       extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
-       auth_extension = e_source_get_extension (source, extension_name);
+       source = e_backend_get_source (backend);
+       auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
        user = e_source_authentication_dup_user (auth_extension);
 
-       gdata_client_login_authorizer_authenticate (
-               GDATA_CLIENT_LOGIN_AUTHORIZER (priv->authorizer),
-               user, password->str, cancellable, &local_error);
+       username = e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME);
+       if (!username || !*username)
+               username = user;
+
+       if (gdata_client_login_authorizer_authenticate (GDATA_CLIENT_LOGIN_AUTHORIZER (priv->authorizer),
+               user, e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_PASSWORD), cancellable, 
&local_error)) {
+               EBookBackend *book_backend = E_BOOK_BACKEND (backend);
+
+               if (gdata_authorizer_refresh_authorization (priv->authorizer, cancellable, &local_error) &&
+                   backend_is_authorized (book_backend)) {
+                       e_book_backend_set_writable (book_backend, TRUE);
+                       cache_refresh_if_needed (book_backend);
+               }
+       }
 
        g_free (user);
 
@@ -2341,7 +2388,8 @@ static void
 e_book_backend_google_class_init (EBookBackendGoogleClass *class)
 {
        GObjectClass *object_class;
-       EBookBackendClass *backend_class;
+       EBackendClass *backend_class;
+       EBookBackendClass *book_backend_class;
 
        g_type_class_add_private (class, sizeof (EBookBackendGooglePrivate));
 
@@ -2349,23 +2397,20 @@ e_book_backend_google_class_init (EBookBackendGoogleClass *class)
        object_class->dispose = book_backend_google_dispose;
        object_class->finalize = book_backend_google_finalize;
 
-       backend_class = E_BOOK_BACKEND_CLASS (class);
-       backend_class->get_backend_property = book_backend_google_get_backend_property;
-       backend_class->open_sync = book_backend_google_open_sync;
-       backend_class->create_contacts_sync = book_backend_google_create_contacts_sync;
-       backend_class->modify_contacts_sync = book_backend_google_modify_contacts_sync;
-       backend_class->remove_contacts_sync = book_backend_google_remove_contacts_sync;
-       backend_class->get_contact_sync = book_backend_google_get_contact_sync;
-       backend_class->get_contact_list_sync = book_backend_google_get_contact_list_sync;
-       backend_class->start_view = book_backend_google_start_view;
-       backend_class->stop_view = book_backend_google_stop_view;
-       backend_class->refresh_sync = book_backend_google_refresh_sync;
-}
-
-static void
-e_book_backend_google_source_authenticator_init (ESourceAuthenticatorInterface *iface)
-{
-       iface->try_password_sync = book_backend_google_try_password_sync;
+       backend_class = E_BACKEND_CLASS (class);
+       backend_class->authenticate_sync = book_backend_google_authenticate_sync;
+
+       book_backend_class = E_BOOK_BACKEND_CLASS (class);
+       book_backend_class->get_backend_property = book_backend_google_get_backend_property;
+       book_backend_class->open_sync = book_backend_google_open_sync;
+       book_backend_class->create_contacts_sync = book_backend_google_create_contacts_sync;
+       book_backend_class->modify_contacts_sync = book_backend_google_modify_contacts_sync;
+       book_backend_class->remove_contacts_sync = book_backend_google_remove_contacts_sync;
+       book_backend_class->get_contact_sync = book_backend_google_get_contact_sync;
+       book_backend_class->get_contact_list_sync = book_backend_google_get_contact_list_sync;
+       book_backend_class->start_view = book_backend_google_start_view;
+       book_backend_class->stop_view = book_backend_google_stop_view;
+       book_backend_class->refresh_sync = book_backend_google_refresh_sync;
 }
 
 static void
diff --git a/addressbook/backends/ldap/e-book-backend-ldap.c b/addressbook/backends/ldap/e-book-backend-ldap.c
index 52ce591..559ebbf 100644
--- a/addressbook/backends/ldap/e-book-backend-ldap.c
+++ b/addressbook/backends/ldap/e-book-backend-ldap.c
@@ -117,17 +117,7 @@ typedef struct LDAPOp LDAPOp;
        "Incorrect msg type %d passed to %s", \
        _msg_type, G_STRFUNC))
 
-/* Forward Declarations */
-static void    e_book_backend_ldap_source_authenticator_init
-                               (ESourceAuthenticatorInterface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (
-       EBookBackendLDAP,
-       e_book_backend_ldap,
-       E_TYPE_BOOK_BACKEND,
-       G_IMPLEMENT_INTERFACE (
-               E_TYPE_SOURCE_AUTHENTICATOR,
-               e_book_backend_ldap_source_authenticator_init))
+G_DEFINE_TYPE (EBookBackendLDAP, e_book_backend_ldap, E_TYPE_BOOK_BACKEND)
 
 struct _EBookBackendLDAPPrivate {
        gboolean connected;
@@ -4940,6 +4930,8 @@ book_backend_ldap_open (EBookBackend *backend,
 
        e_book_backend_set_writable (backend, TRUE);
 
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
+
        auth_required = e_source_authentication_required (auth_extension);
 
        if (!auth_required)
@@ -4953,11 +4945,16 @@ book_backend_ldap_open (EBookBackend *backend,
                auth_required = TRUE;
        }
 
-       if (auth_required && error == NULL)
-               e_backend_authenticate_sync (
-                       E_BACKEND (backend),
-                       E_SOURCE_AUTHENTICATOR (backend),
-                       cancellable, &error);
+       if (auth_required && error == NULL) {
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+
+               e_backend_credentials_required_sync (E_BACKEND (backend), 
E_SOURCE_CREDENTIALS_REASON_REQUIRED,
+                       NULL, 0, NULL, cancellable, &error);
+       } else if (!auth_required && !error) {
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+       } else {
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+       }
 
        if (error != NULL && enable_debug)
                printf ("%s ... failed to connect to server \n", G_STRFUNC);
@@ -5545,10 +5542,12 @@ book_backend_ldap_get_contact_list_uids (EBookBackend *backend,
 }
 
 static ESourceAuthenticationResult
-book_backend_ldap_try_password_sync (ESourceAuthenticator *authenticator,
-                                     const GString *password,
-                                     GCancellable *cancellable,
-                                     GError **error)
+book_backend_ldap_authenticate_sync (EBackend *backend,
+                                    const ENamedParameters *credentials,
+                                    gchar **out_certificate_pem,
+                                    GTlsCertificateFlags *out_certificate_errors,
+                                    GCancellable *cancellable,
+                                    GError **error)
 {
        ESourceAuthenticationResult result;
        EBookBackendLDAP *bl;
@@ -5556,23 +5555,27 @@ book_backend_ldap_try_password_sync (ESourceAuthenticator *authenticator,
        ESource *source;
        gint ldap_error;
        gchar *dn = NULL;
-       const gchar *extension_name;
+       const gchar *username;
        gchar *method;
-       gchar *user;
+       gchar *auth_user;
 
-       bl = E_BOOK_BACKEND_LDAP (authenticator);
-       source = e_backend_get_source (E_BACKEND (authenticator));
+       bl = E_BOOK_BACKEND_LDAP (backend);
+       source = e_backend_get_source (backend);
 
-       extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
-       auth_extension = e_source_get_extension (source, extension_name);
+       auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
 
        /* We should not have gotten here if we're offline. */
        g_return_val_if_fail (
-               e_backend_get_online (E_BACKEND (authenticator)),
+               e_backend_get_online (backend),
                E_SOURCE_AUTHENTICATION_ERROR);
 
        method = e_source_authentication_dup_method (auth_extension);
-       user = e_source_authentication_dup_user (auth_extension);
+       auth_user = e_source_authentication_dup_user (auth_extension);
+
+       username = e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME);
+       if (!username || !*username) {
+               username = auth_user;
+       }
 
        if (!method)
                method = g_strdup ("none");
@@ -5581,7 +5584,7 @@ book_backend_ldap_try_password_sync (ESourceAuthenticator *authenticator,
 
                if (bl->priv->ldap && !strcmp (method, "ldap/simple-email")) {
                        LDAPMessage    *res, *e;
-                       gchar *query = g_strdup_printf ("(mail=%s)", user);
+                       gchar *query = g_strdup_printf ("(mail=%s)", username);
                        gchar *entry_dn;
 
                        g_rec_mutex_lock (&eds_ldap_handler_lock);
@@ -5606,7 +5609,11 @@ book_backend_ldap_try_password_sync (ESourceAuthenticator *authenticator,
                                        error, G_IO_ERROR,
                                        G_IO_ERROR_INVALID_DATA,
                                        _("Failed to get the DN "
-                                       "for user '%s'"), user);
+                                       "for user '%s'"), username);
+
+                               g_free (method);
+                               g_free (auth_user);
+
                                return E_SOURCE_AUTHENTICATION_ERROR;
                        }
 
@@ -5620,14 +5627,14 @@ book_backend_ldap_try_password_sync (ESourceAuthenticator *authenticator,
                        ldap_msgfree (res);
 
                } else if (!g_strcmp0 (method, "ldap/simple-binddn")) {
-                       dn = g_strdup (user);
+                       dn = g_strdup (username);
                }
 
                g_free (bl->priv->auth_dn);
                g_free (bl->priv->auth_secret);
 
                bl->priv->auth_dn = dn;
-               bl->priv->auth_secret = g_strdup (password->str);
+               bl->priv->auth_secret = g_strdup (e_named_parameters_get (credentials, 
E_SOURCE_CREDENTIAL_PASSWORD));
 
                /* now authenticate against the DN we were either supplied or queried for */
                if (enable_debug)
@@ -5642,6 +5649,9 @@ book_backend_ldap_try_password_sync (ESourceAuthenticator *authenticator,
 
                        e_book_backend_ldap_connect (bl, &local_error);
 
+                       g_free (method);
+                       g_free (auth_user);
+
                        if (local_error == NULL) {
                                return E_SOURCE_AUTHENTICATION_ACCEPTED;
 
@@ -5679,7 +5689,7 @@ book_backend_ldap_try_password_sync (ESourceAuthenticator *authenticator,
        }
 #ifdef ENABLE_SASL_BINDS
        else if (!g_ascii_strncasecmp (method, SASL_PREFIX, strlen (SASL_PREFIX))) {
-               g_print ("sasl bind (mech = %s) as %s", method + strlen (SASL_PREFIX), user);
+               g_print ("sasl bind (mech = %s) as %s", method + strlen (SASL_PREFIX), username);
                g_rec_mutex_lock (&eds_ldap_handler_lock);
 
                if (!bl->priv->connected || !bl->priv->ldap) {
@@ -5689,6 +5699,9 @@ book_backend_ldap_try_password_sync (ESourceAuthenticator *authenticator,
 
                        e_book_backend_ldap_connect (bl, &local_error);
 
+                       g_free (method);
+                       g_free (auth_user);
+
                        if (local_error == NULL) {
                                return E_SOURCE_AUTHENTICATION_ACCEPTED;
 
@@ -5723,8 +5736,7 @@ book_backend_ldap_try_password_sync (ESourceAuthenticator *authenticator,
 exit:
        switch (ldap_error) {
                case LDAP_SUCCESS:
-                       e_book_backend_set_writable (
-                               E_BOOK_BACKEND (authenticator), TRUE);
+                       e_book_backend_set_writable (E_BOOK_BACKEND (backend), TRUE);
 
                        /* force a requery on the root dse since some ldap
                         * servers are set up such that they don't report
@@ -5765,7 +5777,7 @@ exit:
        }
 
        g_free (method);
-       g_free (user);
+       g_free (auth_user);
 
        return result;
 }
@@ -5774,7 +5786,8 @@ static void
 e_book_backend_ldap_class_init (EBookBackendLDAPClass *class)
 {
        GObjectClass  *object_class;
-       EBookBackendClass *backend_class;
+       EBackendClass *backend_class;
+       EBookBackendClass *book_backend_class;
 
        g_type_class_add_private (class, sizeof (EBookBackendLDAPPrivate));
 
@@ -5786,30 +5799,27 @@ e_book_backend_ldap_class_init (EBookBackendLDAPClass *class)
        object_class = G_OBJECT_CLASS (class);
        object_class->finalize = book_backend_ldap_finalize;
 
-       backend_class = E_BOOK_BACKEND_CLASS (class);
-       backend_class->get_backend_property = book_backend_ldap_get_backend_property;
-       backend_class->open = book_backend_ldap_open;
-       backend_class->create_contacts = book_backend_ldap_create_contacts;
-       backend_class->modify_contacts = book_backend_ldap_modify_contacts;
-       backend_class->remove_contacts = book_backend_ldap_remove_contacts;
-       backend_class->get_contact = book_backend_ldap_get_contact;
-       backend_class->get_contact_list = book_backend_ldap_get_contact_list;
-       backend_class->get_contact_list_uids = book_backend_ldap_get_contact_list_uids;
-       backend_class->start_view = book_backend_ldap_start_view;
-       backend_class->stop_view = book_backend_ldap_stop_view;
-       backend_class->refresh_sync = book_backend_ldap_refresh_sync;
+       backend_class = E_BACKEND_CLASS (class);
+       backend_class->authenticate_sync = book_backend_ldap_authenticate_sync;
+
+       book_backend_class = E_BOOK_BACKEND_CLASS (class);
+       book_backend_class->get_backend_property = book_backend_ldap_get_backend_property;
+       book_backend_class->open = book_backend_ldap_open;
+       book_backend_class->create_contacts = book_backend_ldap_create_contacts;
+       book_backend_class->modify_contacts = book_backend_ldap_modify_contacts;
+       book_backend_class->remove_contacts = book_backend_ldap_remove_contacts;
+       book_backend_class->get_contact = book_backend_ldap_get_contact;
+       book_backend_class->get_contact_list = book_backend_ldap_get_contact_list;
+       book_backend_class->get_contact_list_uids = book_backend_ldap_get_contact_list_uids;
+       book_backend_class->start_view = book_backend_ldap_start_view;
+       book_backend_class->stop_view = book_backend_ldap_stop_view;
+       book_backend_class->refresh_sync = book_backend_ldap_refresh_sync;
 
        /* Register our ESource extension. */
        E_TYPE_SOURCE_LDAP;
 }
 
 static void
-e_book_backend_ldap_source_authenticator_init (ESourceAuthenticatorInterface *iface)
-{
-       iface->try_password_sync = book_backend_ldap_try_password_sync;
-}
-
-static void
 e_book_backend_ldap_init (EBookBackendLDAP *backend)
 {
        backend->priv = E_BOOK_BACKEND_LDAP_GET_PRIVATE (backend);
diff --git a/addressbook/backends/webdav/e-book-backend-webdav.c 
b/addressbook/backends/webdav/e-book-backend-webdav.c
index 4402a9e..5f130a5 100644
--- a/addressbook/backends/webdav/e-book-backend-webdav.c
+++ b/addressbook/backends/webdav/e-book-backend-webdav.c
@@ -51,17 +51,7 @@
 #define WEBDAV_CONTACT_ETAG "X-EVOLUTION-WEBDAV-ETAG"
 #define WEBDAV_CONTACT_HREF "X-EVOLUTION-WEBDAV-HREF"
 
-/* Forward Declarations */
-static void    e_book_backend_webdav_source_authenticator_init
-                               (ESourceAuthenticatorInterface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (
-       EBookBackendWebdav,
-       e_book_backend_webdav,
-       E_TYPE_BOOK_BACKEND,
-       G_IMPLEMENT_INTERFACE (
-               E_TYPE_SOURCE_AUTHENTICATOR,
-               e_book_backend_webdav_source_authenticator_init))
+G_DEFINE_TYPE (EBookBackendWebdav, e_book_backend_webdav, E_TYPE_BOOK_BACKEND)
 
 struct _EBookBackendWebdavPrivate {
        gboolean           marked_for_offline;
@@ -230,10 +220,7 @@ send_and_handle_ssl (EBookBackendWebdav *webdav,
 {
        guint status_code;
 
-       e_soup_ssl_trust_connect (
-               message, e_backend_get_source (E_BACKEND (webdav)),
-               e_book_backend_get_registry (E_BOOK_BACKEND (webdav)),
-               cancellable);
+       e_soup_ssl_trust_connect (message, e_backend_get_source (E_BACKEND (webdav)));
 
        status_code = soup_session_send_message (webdav->priv->session, message);
 
@@ -1133,7 +1120,7 @@ soup_authenticate (SoupSession *session,
        if (retrying)
                return;
 
-       if (!priv->username || !*priv->username)
+       if (!priv->username || !*priv->username || !priv->password)
                soup_message_set_status (message, SOUP_STATUS_FORBIDDEN);
        else
                soup_auth_authenticate (auth, priv->username, priv->password);
@@ -1221,6 +1208,8 @@ book_backend_webdav_get_backend_property (EBookBackend *backend,
 
 static gboolean
 book_backend_webdav_test_can_connect (EBookBackendWebdav *webdav,
+                                     gchar **out_certificate_pem,
+                                     GTlsCertificateFlags *out_certificate_errors,
                                      GCancellable *cancellable,
                                      GError **error)
 {
@@ -1257,11 +1246,32 @@ book_backend_webdav_test_can_connect (EBookBackendWebdav *webdav,
                                e_client_error_to_string (E_CLIENT_ERROR_AUTHENTICATION_REQUIRED));
                        break;
 
+               case SOUP_STATUS_SSL_FAILED:
+                       if (out_certificate_pem && out_certificate_errors) {
+                               GTlsCertificate *certificate = NULL;
+
+                               g_object_get (G_OBJECT (message),
+                                       "tls-certificate", &certificate,
+                                       "tls-errors", out_certificate_errors,
+                                       NULL);
+
+                               if (certificate) {
+                                       g_object_get (certificate, "certificate-pem", out_certificate_pem, 
NULL);
+                                       g_object_unref (certificate);
+                               }
+                       }
+
+                       g_set_error_literal (
+                               error, SOUP_HTTP_ERROR,
+                               message->status_code,
+                               message->reason_phrase);
+                       break;
+
                default:
-                       g_set_error (
+                       g_set_error_literal (
                                error, SOUP_HTTP_ERROR,
                                message->status_code,
-                               "%s", message->reason_phrase);
+                               message->reason_phrase);
                        break;
        }
 
@@ -1370,13 +1380,55 @@ book_backend_webdav_open_sync (EBookBackend *backend,
        e_backend_set_online (E_BACKEND (backend), TRUE);
        e_book_backend_set_writable (backend, TRUE);
 
-       if (e_source_authentication_required (auth_extension))
-               success = e_backend_authenticate_sync (
-                       E_BACKEND (backend),
-                       E_SOURCE_AUTHENTICATOR (backend),
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
+
+       if (e_source_authentication_required (auth_extension)) {
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+
+               success = e_backend_credentials_required_sync (E_BACKEND (backend),
+                       E_SOURCE_CREDENTIALS_REASON_REQUIRED, NULL, 0, NULL,
                        cancellable, error);
-       else
-               success = book_backend_webdav_test_can_connect (webdav, cancellable, error);
+       } else {
+               gchar *certificate_pem = NULL;
+               GTlsCertificateFlags certificate_errors = 0;
+               GError *local_error = NULL;
+
+               success = book_backend_webdav_test_can_connect (webdav, &certificate_pem, 
&certificate_errors, cancellable, &local_error);
+               if (!success && !g_cancellable_is_cancelled (cancellable)) {
+                       ESourceCredentialsReason reason;
+                       GError *local_error2 = NULL;
+
+                       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+                               reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
+                               e_source_set_connection_status (source, 
E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
+                       } else if (g_error_matches (local_error, E_CLIENT_ERROR, 
E_CLIENT_ERROR_AUTHENTICATION_FAILED) ||
+                                  g_error_matches (local_error, E_CLIENT_ERROR, 
E_CLIENT_ERROR_AUTHENTICATION_REQUIRED)) {
+                               reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
+                       } else {
+                               reason = E_SOURCE_CREDENTIALS_REASON_ERROR;
+                       }
+
+                       if (!e_backend_credentials_required_sync (E_BACKEND (backend), reason, 
certificate_pem, certificate_errors,
+                               local_error, cancellable, &local_error2)) {
+                               g_warning ("%s: Failed to call credentials required: %s", G_STRFUNC, 
local_error2 ? local_error2->message : "Unknown error");
+                       }
+
+                       if (!local_error2 && g_error_matches (local_error, SOUP_HTTP_ERROR, 
SOUP_STATUS_SSL_FAILED)) {
+                               /* These cerificate errors are treated through the authentication */
+                               g_clear_error (&local_error);
+                       } else {
+                               g_propagate_error (error, local_error);
+                               local_error = NULL;
+                       }
+
+                       g_clear_error (&local_error2);
+               }
+
+               g_free (certificate_pem);
+
+               if (local_error)
+                       g_propagate_error (error, local_error);
+       }
 
        soup_uri_free (suri);
 
@@ -1764,31 +1816,49 @@ book_backend_webdav_get_contact_list_sync (EBookBackend *backend,
 }
 
 static ESourceAuthenticationResult
-book_backend_webdav_try_password_sync (ESourceAuthenticator *authenticator,
-                                       const GString *password,
-                                       GCancellable *cancellable,
-                                       GError **error)
+book_backend_webdav_authenticate_sync (EBackend *backend,
+                                      const ENamedParameters *credentials,
+                                      gchar **out_certificate_pem,
+                                      GTlsCertificateFlags *out_certificate_errors,
+                                      GCancellable *cancellable,
+                                      GError **error)
 {
-       EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (authenticator);
+       EBookBackendWebdav *webdav = E_BOOK_BACKEND_WEBDAV (backend);
        ESourceAuthentication *auth_extension;
        ESourceAuthenticationResult result;
        ESource *source;
-       const gchar *extension_name;
+       const gchar *username;
        GError *local_error = NULL;
 
-       source = e_backend_get_source (E_BACKEND (authenticator));
-       extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
-       auth_extension = e_source_get_extension (source, extension_name);
+       source = e_backend_get_source (backend);
+       auth_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
+
+       g_free (webdav->priv->username);
+       webdav->priv->username = NULL;
+
+       g_free (webdav->priv->password);
+       webdav->priv->password = g_strdup (e_named_parameters_get (credentials, 
E_SOURCE_CREDENTIAL_PASSWORD));
 
-       webdav->priv->username =
-               e_source_authentication_dup_user (auth_extension);
-       webdav->priv->password = g_strdup (password->str);
+       username = e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME);
+       if (username && *username) {
+               webdav->priv->username = g_strdup (username);
+       } else {
+               webdav->priv->username = e_source_authentication_dup_user (auth_extension);
+       }
 
-       if (book_backend_webdav_test_can_connect (webdav, cancellable, &local_error)) {
+       if (book_backend_webdav_test_can_connect (webdav, out_certificate_pem, out_certificate_errors, 
cancellable, &local_error)) {
                result = E_SOURCE_AUTHENTICATION_ACCEPTED;
-       } else if (g_error_matches (local_error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED)) {
-               result = E_SOURCE_AUTHENTICATION_REJECTED;
+       } else if (g_error_matches (local_error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_FAILED) ||
+                  g_error_matches (local_error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_REQUIRED)) {
+               if (!e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_PASSWORD) ||
+                   g_error_matches (local_error, E_CLIENT_ERROR, E_CLIENT_ERROR_AUTHENTICATION_REQUIRED))
+                       result = E_SOURCE_AUTHENTICATION_REQUIRED;
+               else
+                       result = E_SOURCE_AUTHENTICATION_REJECTED;
                g_clear_error (&local_error);
+       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+               result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
+               g_propagate_error (error, local_error);
        } else {
                result = E_SOURCE_AUTHENTICATION_ERROR;
                g_propagate_error (error, local_error);
@@ -1801,7 +1871,8 @@ static void
 e_book_backend_webdav_class_init (EBookBackendWebdavClass *class)
 {
        GObjectClass *object_class;
-       EBookBackendClass *backend_class;
+       EBackendClass *backend_class;
+       EBookBackendClass *book_backend_class;
 
        g_type_class_add_private (class, sizeof (EBookBackendWebdavPrivate));
 
@@ -1809,22 +1880,19 @@ e_book_backend_webdav_class_init (EBookBackendWebdavClass *class)
        object_class->dispose = book_backend_webdav_dispose;
        object_class->finalize = book_backend_webdav_finalize;
 
-       backend_class = E_BOOK_BACKEND_CLASS (class);
-       backend_class->get_backend_property = book_backend_webdav_get_backend_property;
-       backend_class->open_sync = book_backend_webdav_open_sync;
-       backend_class->create_contacts_sync = book_backend_webdav_create_contacts_sync;
-       backend_class->modify_contacts_sync = book_backend_webdav_modify_contacts_sync;
-       backend_class->remove_contacts_sync = book_backend_webdav_remove_contacts_sync;
-       backend_class->get_contact_sync = book_backend_webdav_get_contact_sync;
-       backend_class->get_contact_list_sync = book_backend_webdav_get_contact_list_sync;
-       backend_class->start_view = e_book_backend_webdav_start_view;
-       backend_class->stop_view = e_book_backend_webdav_stop_view;
-}
-
-static void
-e_book_backend_webdav_source_authenticator_init (ESourceAuthenticatorInterface *iface)
-{
-       iface->try_password_sync = book_backend_webdav_try_password_sync;
+       backend_class = E_BACKEND_CLASS (class);
+       backend_class->authenticate_sync = book_backend_webdav_authenticate_sync;
+
+       book_backend_class = E_BOOK_BACKEND_CLASS (class);
+       book_backend_class->get_backend_property = book_backend_webdav_get_backend_property;
+       book_backend_class->open_sync = book_backend_webdav_open_sync;
+       book_backend_class->create_contacts_sync = book_backend_webdav_create_contacts_sync;
+       book_backend_class->modify_contacts_sync = book_backend_webdav_modify_contacts_sync;
+       book_backend_class->remove_contacts_sync = book_backend_webdav_remove_contacts_sync;
+       book_backend_class->get_contact_sync = book_backend_webdav_get_contact_sync;
+       book_backend_class->get_contact_list_sync = book_backend_webdav_get_contact_list_sync;
+       book_backend_class->start_view = e_book_backend_webdav_start_view;
+       book_backend_class->stop_view = e_book_backend_webdav_stop_view;
 }
 
 static void
diff --git a/addressbook/libebook/e-book-client.c b/addressbook/libebook/e-book-client.c
index ebd1a2c..609b0a2 100644
--- a/addressbook/libebook/e-book-client.c
+++ b/addressbook/libebook/e-book-client.c
@@ -96,6 +96,7 @@ struct _SignalClosure {
 struct _ConnectClosure {
        ESource *source;
        GCancellable *cancellable;
+       guint32 wait_for_connected_seconds;
 };
 
 struct _RunInThreadClosure {
@@ -1001,6 +1002,34 @@ book_client_refresh_sync (EClient *client,
        return TRUE;
 }
 
+static gboolean
+book_client_retrieve_properties_sync (EClient *client,
+                                     GCancellable *cancellable,
+                                     GError **error)
+{
+       EBookClient *book_client;
+       gchar **properties = NULL;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (E_IS_BOOK_CLIENT (client), FALSE);
+
+       book_client = E_BOOK_CLIENT (client);
+
+       e_dbus_address_book_call_retrieve_properties_sync (
+               book_client->priv->dbus_proxy, &properties, cancellable, &local_error);
+
+       book_client_process_properties (book_client, properties);
+       g_strfreev (properties);
+
+       if (local_error != NULL) {
+               g_dbus_error_strip_remote_error (local_error);
+               g_propagate_error (error, local_error);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
 static void
 book_client_init_in_dbus_thread (GSimpleAsyncResult *simple,
                                  GObject *source_object,
@@ -1246,6 +1275,7 @@ e_book_client_class_init (EBookClientClass *class)
        client_class->set_backend_property_sync = book_client_set_backend_property_sync;
        client_class->open_sync = book_client_open_sync;
        client_class->refresh_sync = book_client_refresh_sync;
+       client_class->retrieve_properties_sync = book_client_retrieve_properties_sync;
 
        /**
         * EBookClient:locale:
@@ -1293,6 +1323,7 @@ e_book_client_init (EBookClient *client)
 /**
  * e_book_client_connect_sync:
  * @source: an #ESource
+ * @wait_for_connected_seconds: timeout, in seconds, to wait for the backend to be fully connected
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
@@ -1302,6 +1333,15 @@ e_book_client_init (EBookClient *client)
  * Unlike with e_book_client_new(), there is no need to call
  * e_client_open_sync() after obtaining the #EBookClient.
  *
+ * The @wait_for_connected_seconds argument had been added since 3.14,
+ * to let the caller decide how long to wait for the backend to fully
+ * connect to its (possibly remote) data store. This is required due
+ * to a change in the authentication process, which is fully asynchronous
+ * and done on the client side, while not every client is supposed to
+ * response to authentication requests. In case the backend will not connect
+ * within the set interval, then it is opened in an offline mode. A special
+ * value -1 can be used to not wait for the connected state at all.
+ *
  * For error handling convenience, any error message returned by this
  * function will have a descriptive prefix that includes the display
  * name of @source.
@@ -1312,6 +1352,7 @@ e_book_client_init (EBookClient *client)
  **/
 EClient *
 e_book_client_connect_sync (ESource *source,
+                           guint32 wait_for_connected_seconds,
                             GCancellable *cancellable,
                             GError **error)
 {
@@ -1336,6 +1377,12 @@ e_book_client_connect_sync (ESource *source,
                g_strfreev (properties);
        }
 
+       if (!local_error && wait_for_connected_seconds != (guint32) -1) {
+               /* These errors are ignored, the book is left opened in an offline mode. */
+               e_client_wait_for_connected_sync (E_CLIENT (client),
+                       wait_for_connected_seconds, cancellable, NULL);
+       }
+
        if (local_error != NULL) {
                g_dbus_error_strip_remote_error (local_error);
                g_propagate_error (error, local_error);
@@ -1349,6 +1396,23 @@ e_book_client_connect_sync (ESource *source,
        return E_CLIENT (client);
 }
 
+static void
+book_client_connect_wait_for_connected_cb (GObject *source_object,
+                                          GAsyncResult *result,
+                                          gpointer user_data)
+{
+       GSimpleAsyncResult *simple;
+
+       simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+       /* These errors are ignored, the book is left opened in an offline mode. */
+       e_client_wait_for_connected_finish (E_CLIENT (source_object), result, NULL);
+
+       g_simple_async_result_complete (simple);
+
+       g_object_unref (simple);
+}
+
 /* Helper for e_book_client_connect() */
 static void
 book_client_connect_open_cb (GObject *source_object,
@@ -1368,6 +1432,24 @@ book_client_connect_open_cb (GObject *source_object,
        client_object = g_async_result_get_source_object (G_ASYNC_RESULT (simple));
        if (client_object) {
                book_client_process_properties (E_BOOK_CLIENT (client_object), properties);
+
+               if (!local_error) {
+                       ConnectClosure *closure;
+
+                       closure = g_simple_async_result_get_op_res_gpointer (simple);
+                       if (closure->wait_for_connected_seconds != (guint32) -1) {
+                               e_client_wait_for_connected (E_CLIENT (client_object),
+                                       closure->wait_for_connected_seconds,
+                                       closure->cancellable,
+                                       book_client_connect_wait_for_connected_cb, g_object_ref (simple));
+
+                               g_clear_object (&client_object);
+                               g_object_unref (simple);
+                               g_strfreev (properties);
+                               return;
+                       }
+               }
+
                g_clear_object (&client_object);
        }
 
@@ -1427,6 +1509,7 @@ exit:
 /**
  * e_book_client_connect:
  * @source: an #ESource
+ * @wait_for_connected_seconds: timeout, in seconds, to wait for the backend to be fully connected
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
  *            is satisfied
@@ -1434,6 +1517,15 @@ exit:
  *
  * Asynchronously creates a new #EBookClient for @source.
  *
+ * The @wait_for_connected_seconds argument had been added since 3.14,
+ * to let the caller decide how long to wait for the backend to fully
+ * connect to its (possibly remote) data store. This is required due
+ * to a change in the authentication process, which is fully asynchronous
+ * and done on the client side, while not every client is supposed to
+ * response to authentication requests. In case the backend will not connect
+ * within the set interval, then it is opened in an offline mode. A special
+ * value -1 can be used to not wait for the connected state at all.
+ *
  * Unlike with e_book_client_new(), there is no need to call e_client_open()
  * after obtaining the #EBookClient.
  *
@@ -1444,6 +1536,7 @@ exit:
  **/
 void
 e_book_client_connect (ESource *source,
+                      guint32 wait_for_connected_seconds,
                        GCancellable *cancellable,
                        GAsyncReadyCallback callback,
                        gpointer user_data)
@@ -1462,6 +1555,7 @@ e_book_client_connect (ESource *source,
 
        closure = g_slice_new0 (ConnectClosure);
        closure->source = g_object_ref (source);
+       closure->wait_for_connected_seconds = wait_for_connected_seconds;
 
        if (G_IS_CANCELLABLE (cancellable))
                closure->cancellable = g_object_ref (cancellable);
@@ -1625,6 +1719,7 @@ connect_direct (EBookClient *client,
  * e_book_client_connect_direct_sync:
  * @registry: an #ESourceRegistry
  * @source: an #ESource
+ * @wait_for_connected_seconds: timeout, in seconds, to wait for the backend to be fully connected
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
@@ -1638,12 +1733,13 @@ connect_direct (EBookClient *client,
 EClient *
 e_book_client_connect_direct_sync (ESourceRegistry *registry,
                                    ESource *source,
+                                  guint32 wait_for_connected_seconds,
                                    GCancellable *cancellable,
                                    GError **error)
 {
        EClient *client;
 
-       client = e_book_client_connect_sync (source, cancellable, error);
+       client = e_book_client_connect_sync (source, wait_for_connected_seconds, cancellable, error);
 
        if (!client)
                return NULL;
@@ -1702,6 +1798,7 @@ exit:
 /**
  * e_book_client_connect_direct:
  * @source: an #ESource
+ * @wait_for_connected_seconds: timeout, in seconds, to wait for the backend to be fully connected
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
  *            is satisfied
@@ -1717,6 +1814,7 @@ exit:
  **/
 void
 e_book_client_connect_direct (ESource *source,
+                             guint32 wait_for_connected_seconds,
                               GCancellable *cancellable,
                               GAsyncReadyCallback callback,
                               gpointer user_data)
@@ -1734,6 +1832,7 @@ e_book_client_connect_direct (ESource *source,
         * time and block other clients from receiving signals. */
        closure = g_slice_new0 (ConnectClosure);
        closure->source = g_object_ref (source);
+       closure->wait_for_connected_seconds = wait_for_connected_seconds;
 
        if (G_IS_CANCELLABLE (cancellable))
                closure->cancellable = g_object_ref (cancellable);
diff --git a/addressbook/libebook/e-book-client.h b/addressbook/libebook/e-book-client.h
index feb3df8..3a557f9 100644
--- a/addressbook/libebook/e-book-client.h
+++ b/addressbook/libebook/e-book-client.h
@@ -102,9 +102,11 @@ struct _EBookClientClass {
 
 GType          e_book_client_get_type          (void) G_GNUC_CONST;
 EClient *      e_book_client_connect_sync      (ESource *source,
+                                                guint32 wait_for_connected_seconds,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           e_book_client_connect           (ESource *source,
+                                                guint32 wait_for_connected_seconds,
                                                 GCancellable *cancellable,
                                                 GAsyncReadyCallback callback,
                                                 gpointer user_data);
@@ -113,9 +115,11 @@ EClient *  e_book_client_connect_finish    (GAsyncResult *result,
 EClient *      e_book_client_connect_direct_sync
                                                (ESourceRegistry *registry,
                                                 ESource *source,
+                                                guint32 wait_for_connected_seconds,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           e_book_client_connect_direct    (ESource *source,
+                                                guint32 wait_for_connected_seconds,
                                                 GCancellable *cancellable,
                                                 GAsyncReadyCallback callback,
                                                 gpointer user_data);
diff --git a/addressbook/libedata-book/e-book-backend.c b/addressbook/libedata-book/e-book-backend.c
index acc6e67..51cc2f4 100644
--- a/addressbook/libedata-book/e-book-backend.c
+++ b/addressbook/libedata-book/e-book-backend.c
@@ -568,24 +568,6 @@ book_backend_constructed (GObject *object)
        }
 }
 
-static gboolean
-book_backend_authenticate_sync (EBackend *backend,
-                                ESourceAuthenticator *auth,
-                                GCancellable *cancellable,
-                                GError **error)
-{
-       EBookBackend *book_backend;
-       ESourceRegistry *registry;
-       ESource *source;
-
-       book_backend = E_BOOK_BACKEND (backend);
-       registry = e_book_backend_get_registry (book_backend);
-       source = e_backend_get_source (backend);
-
-       return e_source_registry_authenticate_sync (
-               registry, source, auth, cancellable, error);
-}
-
 static void
 book_backend_prepare_shutdown (EBackend *backend)
 {
@@ -721,7 +703,6 @@ e_book_backend_class_init (EBookBackendClass *class)
        object_class->constructed = book_backend_constructed;
 
        backend_class = E_BACKEND_CLASS (class);
-       backend_class->authenticate_sync = book_backend_authenticate_sync;
        backend_class->prepare_shutdown = book_backend_prepare_shutdown;
 
        class->get_backend_property = book_backend_get_backend_property;
diff --git a/addressbook/libedata-book/e-data-book.c b/addressbook/libedata-book/e-data-book.c
index 4d66ec7..165fcda 100644
--- a/addressbook/libedata-book/e-data-book.c
+++ b/addressbook/libedata-book/e-data-book.c
@@ -545,24 +545,20 @@ e_data_book_string_slist_to_comma_string (const GSList *strings)
        return res;
 }
 
-static void
-data_book_complete_open_cb (GObject *source_object,
-                            GAsyncResult *result,
-                            gpointer user_data)
+static GPtrArray *
+data_book_encode_properties (EDBusAddressBook *dbus_interface)
 {
-       AsyncContext *async_context = user_data;
-       GError *error = NULL;
+       GPtrArray *properties_array;
 
-       e_book_backend_open_finish (
-               E_BOOK_BACKEND (source_object), result, &error);
+       g_warn_if_fail (E_DBUS_IS_ADDRESS_BOOK (dbus_interface));
 
-       if (error == NULL) {
-               GPtrArray *properties_array;
+       properties_array = g_ptr_array_new_with_free_func (g_free);
+
+       if (dbus_interface) {
                GParamSpec **properties;
                guint ii, n_properties = 0;
 
-               properties_array = g_ptr_array_new_with_free_func (g_free);
-               properties = g_object_class_list_properties (G_OBJECT_GET_CLASS 
(async_context->dbus_interface), &n_properties);
+               properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (dbus_interface), 
&n_properties);
 
                for (ii = 0; ii < n_properties; ii++) {
                        gboolean can_process =
@@ -581,7 +577,7 @@ data_book_complete_open_cb (GObject *source_object,
                                GVariant *stored = NULL;
 
                                g_value_init (&value, properties[ii]->value_type);
-                               g_object_get_property ((GObject *) async_context->dbus_interface, 
properties[ii]->name, &value);
+                               g_object_get_property ((GObject *) dbus_interface, properties[ii]->name, 
&value);
 
                                #define WORKOUT(gvl, gvr) \
                                        if (g_type_is_a (properties[ii]->value_type, G_TYPE_ ## gvl)) \
@@ -611,8 +607,47 @@ data_book_complete_open_cb (GObject *source_object,
                }
 
                g_free (properties);
+       }
+
+       g_ptr_array_add (properties_array, NULL);
+
+       return properties_array;
+}
+
+static gboolean
+data_book_handle_retrieve_properties_cb (EDBusAddressBook *dbus_interface,
+                                        GDBusMethodInvocation *invocation,
+                                        EDataBook *data_book)
+{
+       GPtrArray *properties_array;
+
+       properties_array = data_book_encode_properties (dbus_interface);
+
+       e_dbus_address_book_complete_retrieve_properties (
+               dbus_interface,
+               invocation,
+               (const gchar * const *) properties_array->pdata);
 
-               g_ptr_array_add (properties_array, NULL);
+       g_ptr_array_free (properties_array, TRUE);
+
+       return TRUE;
+}
+
+static void
+data_book_complete_open_cb (GObject *source_object,
+                            GAsyncResult *result,
+                            gpointer user_data)
+{
+       AsyncContext *async_context = user_data;
+       GError *error = NULL;
+
+       e_book_backend_open_finish (
+               E_BOOK_BACKEND (source_object), result, &error);
+
+       if (error == NULL) {
+               GPtrArray *properties_array;
+
+               properties_array = data_book_encode_properties (async_context->dbus_interface);
 
                e_dbus_address_book_complete_open (
                        async_context->dbus_interface,
@@ -2066,6 +2101,10 @@ e_data_book_init (EDataBook *data_book)
                (GDestroyNotify) g_ptr_array_unref);
 
        g_signal_connect (
+               dbus_interface, "handle-retrieve-properties",
+               G_CALLBACK (data_book_handle_retrieve_properties_cb),
+               data_book);
+       g_signal_connect (
                dbus_interface, "handle-open",
                G_CALLBACK (data_book_handle_open_cb),
                data_book);
diff --git a/calendar/backends/caldav/e-cal-backend-caldav.c b/calendar/backends/caldav/e-cal-backend-caldav.c
index a4425a5..192260b 100644
--- a/calendar/backends/caldav/e-cal-backend-caldav.c
+++ b/calendar/backends/caldav/e-cal-backend-caldav.c
@@ -95,9 +95,9 @@ struct _ECalBackendCalDAVPrivate {
        gchar *uri;
 
        /* Authentication info */
+       gchar *username; /* not NULL only as override */
        gchar *password;
        gboolean auth_required;
-       gboolean force_ask_password;
 
        /* support for 'getctag' extension */
        gboolean ctag_supported;
@@ -122,7 +122,7 @@ struct _ECalBackendCalDAVPrivate {
 
        /* If we fail to obtain an OAuth2 access token,
         * soup_authenticate_bearer() stashes an error
-        * here to be claimed in caldav_authenticate().
+        * here to be claimed in caldav_credentials_required_sync().
         * This lets us propagate a more useful error
         * message than a generic 401 description. */
        GError *bearer_auth_error;
@@ -132,8 +132,6 @@ struct _ECalBackendCalDAVPrivate {
 /* Forward Declarations */
 static void    e_caldav_backend_initable_init
                                (GInitableIface *interface);
-static void    caldav_source_authenticator_init
-                               (ESourceAuthenticatorInterface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (
        ECalBackendCalDAV,
@@ -141,10 +139,7 @@ G_DEFINE_TYPE_WITH_CODE (
        E_TYPE_CAL_BACKEND_SYNC,
        G_IMPLEMENT_INTERFACE (
                G_TYPE_INITABLE,
-               e_caldav_backend_initable_init)
-       G_IMPLEMENT_INTERFACE (
-               E_TYPE_SOURCE_AUTHENTICATOR,
-               caldav_source_authenticator_init))
+               e_caldav_backend_initable_init))
 
 /* ************************************************************************* */
 /* Debugging */
@@ -155,7 +150,13 @@ G_DEFINE_TYPE_WITH_CODE (
 #define DEBUG_SERVER_ITEMS "items"
 #define DEBUG_ATTACHMENTS "attachments"
 
-static gboolean open_calendar_wrapper (ECalBackendCalDAV *cbdav, GCancellable *cancellable, GError **error, 
gboolean can_call_authenticate, gboolean *know_unreachable);
+static gboolean open_calendar_wrapper (ECalBackendCalDAV *cbdav,
+                                      GCancellable *cancellable,
+                                      GError **error,
+                                      gboolean first_attempt,
+                                      gboolean *know_unreachable,
+                                      gchar **out_certificate_pem,
+                                      GTlsCertificateFlags *out_certificate_errors);
 
 static void convert_to_inline_attachment (ECalBackendCalDAV *cbdav, icalcomponent *icalcomp);
 static void convert_to_url_attachment (ECalBackendCalDAV *cbdav, icalcomponent *icalcomp);
@@ -609,6 +610,10 @@ status_code_to_result (SoupMessage *message,
                        _("Failed to connect to a server using SSL: %s"),
                        message->reason_phrase && *message->reason_phrase ? message->reason_phrase :
                        (soup_status_get_phrase (message->status_code) ? soup_status_get_phrase 
(message->status_code) : _("Unknown error"))));
+               if (is_opening && perror && *perror) {
+                       (*perror)->domain = SOUP_HTTP_ERROR;
+                       (*perror)->code = SOUP_STATUS_SSL_FAILED;
+               }
                break;
 
        default:
@@ -997,7 +1002,7 @@ soup_authenticate_bearer (SoupSession *session,
                E_SOUP_AUTH_BEARER (auth),
                access_token, expires_in_seconds);
 
-       /* Stash the error to be picked up by caldav_authenticate().
+       /* Stash the error to be picked up by caldav_credentials_required_sync().
         * There's no way to explicitly propagate a GError directly
         * through libsoup, so we have to work around it. */
        if (local_error != NULL) {
@@ -1036,24 +1041,29 @@ soup_authenticate (SoupSession *session,
        extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
        auth_extension = e_source_get_extension (source, extension_name);
 
-       if (retrying || cbdav->priv->force_ask_password) {
-               cbdav->priv->force_ask_password = TRUE;
+       if (retrying)
                return;
-       }
 
        if (E_IS_SOUP_AUTH_BEARER (auth)) {
                soup_authenticate_bearer (session, msg, auth, cbdav);
 
        /* do not send same password twice, but keep it for later use */
-       } else if (cbdav->priv->password != NULL) {
-               gchar *user;
+       } else {
+               gchar *auth_user;
+               const gchar *username;
 
-               user = e_source_authentication_dup_user (auth_extension);
-               if (!user || !*user)
+               auth_user = e_source_authentication_dup_user (auth_extension);
+
+               username = cbdav->priv->username;
+               if (!username || !*username)
+                       username = auth_user;
+
+               if (!username || !*username || !cbdav->priv->password)
                        soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
                else
-                       soup_auth_authenticate (auth, user, cbdav->priv->password);
-               g_free (user);
+                       soup_auth_authenticate (auth, username, cbdav->priv->password);
+
+               g_free (auth_user);
        }
 }
 
@@ -1110,10 +1120,7 @@ send_and_handle_redirection (ECalBackendCalDAV *cbdav,
        if (new_location)
                old_uri = soup_uri_to_string (soup_message_get_uri (msg), FALSE);
 
-       e_soup_ssl_trust_connect (
-               msg, e_backend_get_source (E_BACKEND (cbdav)),
-               e_cal_backend_get_registry (E_CAL_BACKEND (cbdav)),
-               cancellable);
+       e_soup_ssl_trust_connect (msg, e_backend_get_source (E_BACKEND (cbdav)));
 
        soup_message_set_flags (msg, SOUP_MESSAGE_NO_REDIRECT);
        soup_message_add_header_handler (msg, "got_body", "Location", G_CALLBACK (redirect_handler), 
cbdav->priv->session);
@@ -1152,6 +1159,8 @@ caldav_generate_uri (ECalBackendCalDAV *cbdav,
 static gboolean
 caldav_server_open_calendar (ECalBackendCalDAV *cbdav,
                              gboolean *server_unreachable,
+                            gchar **out_certificate_pem,
+                            GTlsCertificateFlags *out_certificate_errors,
                              GCancellable *cancellable,
                              GError **perror)
 {
@@ -1161,7 +1170,6 @@ caldav_server_open_calendar (ECalBackendCalDAV *cbdav,
        gboolean put_allowed;
        gboolean delete_allowed;
        ESource *source;
-       ESourceWebdav *webdav_extension;
 
        g_return_val_if_fail (cbdav != NULL, FALSE);
        g_return_val_if_fail (server_unreachable != NULL, FALSE);
@@ -1171,22 +1179,39 @@ caldav_server_open_calendar (ECalBackendCalDAV *cbdav,
                g_propagate_error (perror, EDC_ERROR (NoSuchCal));
                return FALSE;
        }
+
        soup_message_headers_append (
                message->request_headers,
                "User-Agent", "Evolution/" VERSION);
 
        source = e_backend_get_source (E_BACKEND (cbdav));
-       webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
-       e_source_webdav_unset_temporary_ssl_trust (webdav_extension);
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
 
        send_and_handle_redirection (cbdav, message, NULL, cancellable, perror);
 
        if (!SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+
                switch (message->status_code) {
                case SOUP_STATUS_CANT_CONNECT:
                case SOUP_STATUS_CANT_CONNECT_PROXY:
                        *server_unreachable = TRUE;
                        break;
+               case SOUP_STATUS_SSL_FAILED:
+                       if (out_certificate_pem && out_certificate_errors) {
+                               GTlsCertificate *certificate = NULL;
+
+                               g_object_get (G_OBJECT (message),
+                                       "tls-certificate", &certificate,
+                                       "tls-errors", out_certificate_errors,
+                                       NULL);
+
+                               if (certificate) {
+                                       g_object_get (certificate, "certificate-pem", out_certificate_pem, 
NULL);
+                                       g_object_unref (certificate);
+                               }
+                       }
+                       break;
                }
 
                status_code_to_result (message, cbdav, TRUE, perror);
@@ -1218,12 +1243,14 @@ caldav_server_open_calendar (ECalBackendCalDAV *cbdav,
        g_object_unref (message);
 
        if (calendar_access) {
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
                e_cal_backend_set_writable (
                        E_CAL_BACKEND (cbdav),
                        put_allowed && delete_allowed);
                return TRUE;
        }
 
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
        g_propagate_error (perror, EDC_ERROR (PermissionDenied));
        return FALSE;
 }
@@ -1248,10 +1275,11 @@ caldav_unref_in_thread (ECalBackendCalDAV *cbdav)
 }
 
 static gboolean
-caldav_authenticate (ECalBackendCalDAV *cbdav,
-                     gboolean ref_cbdav,
-                     GCancellable *cancellable,
-                     GError **error)
+caldav_credentials_required_sync (ECalBackendCalDAV *cbdav,
+                                 gboolean ref_cbdav,
+                                 gboolean first_attempt,
+                                 GCancellable *cancellable,
+                                 GError **error)
 {
        gboolean success = TRUE;
 
@@ -1271,10 +1299,10 @@ caldav_authenticate (ECalBackendCalDAV *cbdav,
        g_mutex_unlock (&cbdav->priv->bearer_auth_error_lock);
 
        if (success) {
-               success = e_backend_authenticate_sync (
-                       E_BACKEND (cbdav),
-                       E_SOURCE_AUTHENTICATOR (cbdav),
-                       cancellable, error);
+               success = e_backend_credentials_required_sync (E_BACKEND (cbdav),
+                       (first_attempt || !cbdav->priv->password) ? E_SOURCE_CREDENTIALS_REASON_REQUIRED :
+                       E_SOURCE_CREDENTIALS_REASON_REJECTED,
+                       NULL, 0, NULL, cancellable, error);
        }
 
        if (ref_cbdav)
@@ -1359,7 +1387,7 @@ check_calendar_changed_on_server (ECalBackendCalDAV *cbdav,
 
        /* Check the result */
        if (message->status_code == 401) {
-               caldav_authenticate (cbdav, TRUE, NULL, NULL);
+               caldav_credentials_required_sync (cbdav, TRUE, FALSE, NULL, NULL);
        } else if (message->status_code != 207) {
                /* does not support it, but report calendar changed to update cache */
                cbdav->priv->ctag_supported = FALSE;
@@ -1521,7 +1549,7 @@ caldav_server_list_objects (ECalBackendCalDAV *cbdav,
                                E_CAL_BACKEND (cbdav), FALSE);
                        break;
                case 401:
-                       caldav_authenticate (cbdav, TRUE, NULL, NULL);
+                       caldav_credentials_required_sync (cbdav, TRUE, FALSE, NULL, NULL);
                        break;
                default:
                        g_warning ("Server did not response with 207, but with code %d (%s)", 
message->status_code, soup_status_get_phrase (message->status_code) ? soup_status_get_phrase 
(message->status_code) : "Unknown code");
@@ -1644,7 +1672,7 @@ caldav_server_query_for_uid (ECalBackendCalDAV *cbdav,
                                E_CAL_BACKEND (cbdav), FALSE);
                        break;
                case 401:
-                       caldav_authenticate (cbdav, TRUE, NULL, NULL);
+                       caldav_credentials_required_sync (cbdav, TRUE, FALSE, NULL, NULL);
                        break;
                default:
                        g_warning ("Server did not response with 207, but with code %d (%s)", 
message->status_code, soup_status_get_phrase (message->status_code) ? soup_status_get_phrase 
(message->status_code) : "Unknown code");
@@ -1709,7 +1737,7 @@ caldav_server_download_attachment (ECalBackendCalDAV *cbdav,
                status_code_to_result (message, cbdav, FALSE, error);
 
                if (message->status_code == 401)
-                       caldav_authenticate (cbdav, FALSE, NULL, NULL);
+                       caldav_credentials_required_sync (cbdav, FALSE, FALSE, NULL, NULL);
 
                g_object_unref (message);
                return FALSE;
@@ -1753,7 +1781,7 @@ caldav_server_get_object (ECalBackendCalDAV *cbdav,
                status_code_to_result (message, cbdav, FALSE, perror);
 
                if (message->status_code == 401)
-                       caldav_authenticate (cbdav, FALSE, NULL, NULL);
+                       caldav_credentials_required_sync (cbdav, FALSE, FALSE, NULL, NULL);
                else
                        g_warning ("Could not fetch object '%s' from server, status:%d (%s)", uri, 
message->status_code, soup_status_get_phrase (message->status_code) ? soup_status_get_phrase 
(message->status_code) : "Unknown code");
                g_object_unref (message);
@@ -1816,7 +1844,7 @@ caldav_post_freebusy (ECalBackendCalDAV *cbdav,
        if (!SOUP_STATUS_IS_SUCCESSFUL (message->status_code)) {
                status_code_to_result (message, cbdav, FALSE, error);
                if (message->status_code == 401)
-                       caldav_authenticate (cbdav, FALSE, NULL, NULL);
+                       caldav_credentials_required_sync (cbdav, FALSE, FALSE, NULL, NULL);
                else
                        g_warning ("Could not post free/busy request to '%s', status:%d (%s)", url, 
message->status_code, soup_status_get_phrase (message->status_code) ? soup_status_get_phrase 
(message->status_code) : "Unknown code");
 
@@ -2008,7 +2036,7 @@ caldav_server_put_object (ECalBackendCalDAV *cbdav,
                        g_propagate_error (perror, local_error);
                }
        } else if (message->status_code == 401) {
-               caldav_authenticate (cbdav, FALSE, NULL, NULL);
+               caldav_credentials_required_sync (cbdav, FALSE, FALSE, NULL, NULL);
        }
 
        g_object_unref (message);
@@ -2050,7 +2078,7 @@ caldav_server_delete_object (ECalBackendCalDAV *cbdav,
        status_code_to_result (message, cbdav, FALSE, perror);
 
        if (message->status_code == 401)
-               caldav_authenticate (cbdav, FALSE, NULL, NULL);
+               caldav_credentials_required_sync (cbdav, FALSE, FALSE, NULL, NULL);
 
        g_object_unref (message);
 }
@@ -2171,7 +2199,7 @@ caldav_receive_schedule_outbox_url (ECalBackendCalDAV *cbdav,
                xmlOutputBufferClose (buf);
                xmlFreeDoc (doc);
        } else if (message->status_code == 401) {
-               caldav_authenticate (cbdav, FALSE, NULL, NULL);
+               caldav_credentials_required_sync (cbdav, FALSE, FALSE, NULL, NULL);
        }
 
        if (message)
@@ -2536,7 +2564,7 @@ caldav_synch_slave_loop (gpointer data)
                }
 
                if (!cbdav->priv->opened) {
-                       if (open_calendar_wrapper (cbdav, NULL, NULL, TRUE, &know_unreachable)) {
+                       if (open_calendar_wrapper (cbdav, NULL, NULL, TRUE, &know_unreachable, NULL, NULL)) {
                                cbdav->priv->opened = TRUE;
                                update_slave_cmd (cbdav->priv, SLAVE_SHOULD_WORK);
                                g_cond_signal (&cbdav->priv->cond);
@@ -2877,27 +2905,33 @@ static gboolean
 open_calendar_wrapper (ECalBackendCalDAV *cbdav,
                       GCancellable *cancellable,
                       GError **error,
-                      gboolean can_call_authenticate,
-                      gboolean *know_unreachable)
+                      gboolean first_attempt,
+                      gboolean *know_unreachable,
+                      gchar **out_certificate_pem,
+                      GTlsCertificateFlags *out_certificate_errors)
 {
        gboolean server_unreachable = FALSE;
+       gboolean awaiting_credentials = FALSE;
        gboolean success;
        GError *local_error = NULL;
 
        g_return_val_if_fail (cbdav != NULL, FALSE);
 
-       success = caldav_server_open_calendar (cbdav, &server_unreachable, cancellable, &local_error);
+       success = caldav_server_open_calendar (cbdav, &server_unreachable, out_certificate_pem, 
out_certificate_errors, cancellable, &local_error);
 
-       if (can_call_authenticate && g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationFailed)) {
+       if (first_attempt && g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationFailed)) {
                g_clear_error (&local_error);
-               success = caldav_authenticate (cbdav, FALSE, cancellable, &local_error);
+               awaiting_credentials = TRUE;
+               success = caldav_credentials_required_sync (cbdav, FALSE, first_attempt, cancellable, 
&local_error);
        }
 
        if (success) {
-               update_slave_cmd (cbdav->priv, SLAVE_SHOULD_WORK);
-               g_cond_signal (&cbdav->priv->cond);
-
                cbdav->priv->is_google = is_google_uri (cbdav->priv->uri);
+
+               if (!awaiting_credentials) {
+                       update_slave_cmd (cbdav->priv, SLAVE_SHOULD_WORK);
+                       g_cond_signal (&cbdav->priv->cond);
+               }
        } else if (server_unreachable) {
                cbdav->priv->opened = FALSE;
                e_cal_backend_set_writable (E_CAL_BACKEND (cbdav), FALSE);
@@ -2930,13 +2964,19 @@ caldav_do_open (ECalBackendSync *backend,
                 gboolean only_if_exists,
                 GError **perror)
 {
-       ECalBackendCalDAV        *cbdav;
+       ECalBackendCalDAV *cbdav;
+       ESourceWebdav *webdav_extension;
+       ESource *source;
        gboolean online;
 
        cbdav = E_CAL_BACKEND_CALDAV (backend);
 
        g_mutex_lock (&cbdav->priv->busy_lock);
 
+       source = e_backend_get_source (E_BACKEND (cbdav));
+       webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
+       e_source_webdav_unset_temporary_ssl_trust (webdav_extension);
+
        /* let it decide the 'getctag' extension availability again */
        cbdav->priv->ctag_supported = TRUE;
 
@@ -2958,7 +2998,39 @@ caldav_do_open (ECalBackendSync *backend,
        cbdav->priv->is_google = FALSE;
 
        if (online) {
-               open_calendar_wrapper (cbdav, cancellable, perror, TRUE, NULL);
+               gchar *certificate_pem = NULL;
+               GTlsCertificateFlags certificate_errors = 0;
+               GError *local_error = NULL;
+
+               if (!open_calendar_wrapper (cbdav, cancellable, &local_error, TRUE, NULL, &certificate_pem, 
&certificate_errors) &&
+                   !g_cancellable_is_cancelled (cancellable)) {
+                       ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
+                       GError *local_error2 = NULL;
+
+                       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+                               reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
+                       }
+
+                       if (!e_backend_credentials_required_sync (E_BACKEND (backend), reason, 
certificate_pem, certificate_errors,
+                               local_error, cancellable, &local_error2)) {
+                               g_warning ("%s: Failed to call credentials required: %s", G_STRFUNC, 
local_error2 ? local_error2->message : "Unknown error");
+                       }
+
+                       if (!local_error2 && (
+                           g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED) ||
+                           g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationRequired) ||
+                           g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationFailed))) {
+                               /* These errors are treated through the authentication */
+                               g_clear_error (&local_error);
+                       } else {
+                               g_propagate_error (perror, local_error);
+                               local_error = NULL;
+                       }
+                       g_clear_error (&local_error2);
+               }
+
+               g_clear_error (&local_error);
+               g_free (certificate_pem);
        } else {
                e_cal_backend_set_writable (E_CAL_BACKEND (cbdav), FALSE);
        }
@@ -5249,46 +5321,59 @@ caldav_source_changed_cb (ESource *source,
 }
 
 static ESourceAuthenticationResult
-caldav_try_password_sync (ESourceAuthenticator *authenticator,
-                          const GString *password,
-                          GCancellable *cancellable,
-                          GError **error)
+caldav_authenticate_sync (EBackend *backend,
+                         const ENamedParameters *credentials,
+                         gchar **out_certificate_pem,
+                         GTlsCertificateFlags *out_certificate_errors,
+                         GCancellable *cancellable,
+                         GError **error)
 {
        ECalBackendCalDAV *cbdav;
        ESourceAuthenticationResult result;
+       const gchar *username;
        GError *local_error = NULL;
 
-       cbdav = E_CAL_BACKEND_CALDAV (authenticator);
+       cbdav = E_CAL_BACKEND_CALDAV (backend);
 
-       /* Busy lock is already acquired by caldav_do_open(). */
+       g_mutex_lock (&cbdav->priv->busy_lock);
 
-       if (cbdav->priv->force_ask_password) {
-               cbdav->priv->force_ask_password = FALSE;
-               return E_SOURCE_AUTHENTICATION_REJECTED;
-       }
+       g_free (cbdav->priv->username);
+       cbdav->priv->username = NULL;
 
        g_free (cbdav->priv->password);
-       cbdav->priv->password = g_strdup (password->str);
+       cbdav->priv->password = g_strdup (e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_PASSWORD));
 
-       open_calendar_wrapper (cbdav, cancellable, &local_error, FALSE, NULL);
+       username = e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME);
+       if (username && *username) {
+               cbdav->priv->username = g_strdup (username);
+       }
+
+       open_calendar_wrapper (cbdav, cancellable, &local_error, FALSE, NULL, out_certificate_pem, 
out_certificate_errors);
 
        if (local_error == NULL) {
                result = E_SOURCE_AUTHENTICATION_ACCEPTED;
-       } else if (g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationFailed)) {
-               result = E_SOURCE_AUTHENTICATION_REJECTED;
+
+               update_slave_cmd (cbdav->priv, SLAVE_SHOULD_WORK);
+               g_cond_signal (&cbdav->priv->cond);
+       } else if (g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationFailed) ||
+                  g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationRequired)) {
+               if (!e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_PASSWORD) ||
+                   g_error_matches (local_error, E_DATA_CAL_ERROR, AuthenticationRequired))
+                       result = E_SOURCE_AUTHENTICATION_REQUIRED;
+               else
+                       result = E_SOURCE_AUTHENTICATION_REJECTED;
                g_clear_error (&local_error);
+       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+               result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
+               g_propagate_error (error, local_error);
        } else {
                result = E_SOURCE_AUTHENTICATION_ERROR;
                g_propagate_error (error, local_error);
        }
 
-       return result;
-}
+       g_mutex_unlock (&cbdav->priv->busy_lock);
 
-static void
-caldav_source_authenticator_init (ESourceAuthenticatorInterface *iface)
-{
-       iface->try_password_sync = caldav_try_password_sync;
+       return result;
 }
 
 /* ************************************************************************* */
@@ -5320,6 +5405,7 @@ e_cal_backend_caldav_finalize (GObject *object)
        g_cond_clear (&priv->slave_gone_cond);
 
        g_free (priv->uri);
+       g_free (priv->username);
        g_free (priv->password);
        g_free (priv->schedule_outbox_url);
 
@@ -5456,12 +5542,14 @@ static void
 e_cal_backend_caldav_class_init (ECalBackendCalDAVClass *class)
 {
        GObjectClass *object_class;
-       ECalBackendClass *backend_class;
+       EBackendClass *backend_class;
+       ECalBackendClass *cal_backend_class;
        ECalBackendSyncClass *sync_class;
 
-       object_class = (GObjectClass *) class;
-       backend_class = (ECalBackendClass *) class;
-       sync_class = (ECalBackendSyncClass *) class;
+       object_class = G_OBJECT_CLASS (class);
+       backend_class = E_BACKEND_CLASS (class);
+       cal_backend_class = E_CAL_BACKEND_CLASS (class);
+       sync_class = E_CAL_BACKEND_SYNC_CLASS (class);
 
        caldav_debug_init ();
 
@@ -5471,8 +5559,11 @@ e_cal_backend_caldav_class_init (ECalBackendCalDAVClass *class)
        object_class->dispose = e_cal_backend_caldav_dispose;
        object_class->finalize = e_cal_backend_caldav_finalize;
 
-       backend_class->get_backend_property = caldav_get_backend_property;
-       backend_class->shutdown = caldav_shutdown;
+       backend_class->authenticate_sync = caldav_authenticate_sync;
+
+       cal_backend_class->get_backend_property = caldav_get_backend_property;
+       cal_backend_class->shutdown = caldav_shutdown;
+       cal_backend_class->start_view = caldav_start_view;
 
        sync_class->open_sync = caldav_do_open;
        sync_class->refresh_sync = caldav_refresh;
@@ -5487,8 +5578,6 @@ e_cal_backend_caldav_class_init (ECalBackendCalDAVClass *class)
        sync_class->get_object_list_sync = caldav_get_object_list;
        sync_class->add_timezone_sync = caldav_add_timezone;
        sync_class->get_free_busy_sync = caldav_get_free_busy;
-
-       backend_class->start_view = caldav_start_view;
 }
 
 static void
diff --git a/calendar/backends/contacts/e-cal-backend-contacts.c 
b/calendar/backends/contacts/e-cal-backend-contacts.c
index 6080478..2ab4b6b 100644
--- a/calendar/backends/contacts/e-cal-backend-contacts.c
+++ b/calendar/backends/contacts/e-cal-backend-contacts.c
@@ -144,7 +144,7 @@ create_book_record (ECalBackendContacts *cbc,
        br->cbc = g_object_ref (cbc);
 
        e_book_client_connect (
-               source, NULL, book_client_connected_cb, br);
+               source, 30, NULL, book_client_connected_cb, br);
 }
 
 static BookRecord *
@@ -1146,6 +1146,10 @@ e_cal_backend_contacts_open (ECalBackendSync *backend,
        if (priv->addressbook_loaded)
                return;
 
+       /* Local source is always connected. */
+       e_source_set_connection_status (e_backend_get_source (E_BACKEND (backend)),
+               E_SOURCE_CONNECTION_STATUS_CONNECTED);
+
        priv->addressbook_loaded = TRUE;
        e_cal_backend_set_writable (E_CAL_BACKEND (backend), FALSE);
        e_backend_set_online (E_BACKEND (backend), TRUE);
diff --git a/calendar/backends/file/e-cal-backend-file.c b/calendar/backends/file/e-cal-backend-file.c
index e777379..e0b16a2 100644
--- a/calendar/backends/file/e-cal-backend-file.c
+++ b/calendar/backends/file/e-cal-backend-file.c
@@ -1381,6 +1381,10 @@ e_cal_backend_file_open (ECalBackendSync *backend,
        priv = cbfile->priv;
        g_rec_mutex_lock (&priv->idle_save_rmutex);
 
+       /* Local source is always connected. */
+       e_source_set_connection_status (e_backend_get_source (E_BACKEND (backend)),
+               E_SOURCE_CONNECTION_STATUS_CONNECTED);
+
        /* Claim a succesful open if we are already open */
        if (priv->path && priv->comp_uid_hash) {
                /* Success */
diff --git a/calendar/backends/gtasks/e-cal-backend-gtasks.c b/calendar/backends/gtasks/e-cal-backend-gtasks.c
index 2e668e4..63e4e6d 100644
--- a/calendar/backends/gtasks/e-cal-backend-gtasks.c
+++ b/calendar/backends/gtasks/e-cal-backend-gtasks.c
@@ -678,11 +678,9 @@ ecb_gtasks_request_authorization (ECalBackend *backend,
        if (!GDATA_IS_CLIENT_LOGIN_AUTHORIZER (gtasks->priv->authorizer))
                return TRUE;
 
-       /* Otherwise it's up to us to obtain a login secret. */
-       return e_backend_authenticate_sync (
-               E_BACKEND (backend),
-               E_SOURCE_AUTHENTICATOR (backend),
-               cancellable, error);
+       /* Otherwise it's up to us to obtain a login secret, but
+          there is currently no way to do it, thus simply fail. */
+       return FALSE;
 }
 
 static gchar *
diff --git a/calendar/backends/http/e-cal-backend-http.c b/calendar/backends/http/e-cal-backend-http.c
index c13fe19..38599d7 100644
--- a/calendar/backends/http/e-cal-backend-http.c
+++ b/calendar/backends/http/e-cal-backend-http.c
@@ -34,17 +34,7 @@
 #define EDC_ERROR(_code) e_data_cal_create_error (_code, NULL)
 #define EDC_ERROR_EX(_code, _msg) e_data_cal_create_error (_code, _msg)
 
-/* Forward Declarations */
-static void    e_cal_backend_http_source_authenticator_init
-                               (ESourceAuthenticatorInterface *iface);
-
-G_DEFINE_TYPE_WITH_CODE (
-       ECalBackendHttp,
-       e_cal_backend_http,
-       E_TYPE_CAL_BACKEND_SYNC,
-       G_IMPLEMENT_INTERFACE (
-               E_TYPE_SOURCE_AUTHENTICATOR,
-               e_cal_backend_http_source_authenticator_init))
+G_DEFINE_TYPE (ECalBackendHttp, e_cal_backend_http, E_TYPE_CAL_BACKEND_SYNC)
 
 /* Private part of the ECalBackendHttp structure */
 struct _ECalBackendHttpPrivate {
@@ -67,6 +57,7 @@ struct _ECalBackendHttpPrivate {
        gboolean opened;
        gboolean requires_auth;
 
+       gchar *username;
        gchar *password;
 };
 
@@ -89,7 +80,8 @@ soup_authenticate (SoupSession *session,
        ESourceAuthentication *auth_extension;
        ESource *source;
        const gchar *extension_name;
-       gchar *user;
+       const gchar *username;
+       gchar *auth_user;
 
        if (retrying)
                return;
@@ -100,14 +92,18 @@ soup_authenticate (SoupSession *session,
        extension_name = E_SOURCE_EXTENSION_AUTHENTICATION;
        auth_extension = e_source_get_extension (source, extension_name);
 
-       user = e_source_authentication_dup_user (auth_extension);
+       auth_user = e_source_authentication_dup_user (auth_extension);
 
-       if (!user || !*user)
+       username = cbhttp->priv->username;
+       if (!username || !*username)
+               username = auth_user;
+
+       if (!username || !*username || !cbhttp->priv->password)
                soup_message_set_status (msg, SOUP_STATUS_FORBIDDEN);
-       else if (cbhttp->priv->password != NULL)
-               soup_auth_authenticate (auth, user, cbhttp->priv->password);
+       else
+               soup_auth_authenticate (auth, username, cbhttp->priv->password);
 
-       g_free (user);
+       g_free (auth_user);
 }
 
 /* Dispose handler for the file backend */
@@ -158,6 +154,7 @@ e_cal_backend_http_finalize (GObject *object)
        }
 
        g_free (priv->uri);
+       g_free (priv->username);
        g_free (priv->password);
 
        /* Chain up to parent's finalize() method. */
@@ -453,10 +450,35 @@ cal_backend_http_cancelled (GCancellable *cancellable,
                SOUP_STATUS_CANCELLED);
 }
 
+static void
+cal_backend_http_extract_ssl_failed_data (SoupMessage *msg,
+                                         gchar **out_certificate_pem,
+                                         GTlsCertificateFlags *out_certificate_errors)
+{
+       GTlsCertificate *certificate = NULL;
+
+       g_return_if_fail (SOUP_IS_MESSAGE (msg));
+
+       if (!out_certificate_pem || !out_certificate_errors)
+               return;
+
+       g_object_get (G_OBJECT (msg),
+               "tls-certificate", &certificate,
+               "tls-errors", out_certificate_errors,
+               NULL);
+
+       if (certificate) {
+               g_object_get (certificate, "certificate-pem", out_certificate_pem, NULL);
+               g_object_unref (certificate);
+       }
+}
+
 static gboolean
 cal_backend_http_load (ECalBackendHttp *backend,
-                       GCancellable *cancellable,
                        const gchar *uri,
+                      gchar **out_certificate_pem,
+                      GTlsCertificateFlags *out_certificate_errors,
+                       GCancellable *cancellable,
                        GError **error)
 {
        ECalBackendHttpPrivate *priv = backend->priv;
@@ -469,6 +491,7 @@ cal_backend_http_load (ECalBackendHttp *backend,
        SoupURI *uri_parsed;
        GHashTable *old_cache;
        GSList *comps_in_cache;
+       ESource *source;
        guint status_code;
        gulong cancel_id = 0;
 
@@ -500,10 +523,11 @@ cal_backend_http_load (ECalBackendHttp *backend,
                        &cancel_data, (GDestroyNotify) NULL);
        }
 
-       e_soup_ssl_trust_connect (
-               soup_message, e_backend_get_source (E_BACKEND (backend)),
-               e_cal_backend_get_registry (E_CAL_BACKEND (backend)),
-               cancellable);
+       source = e_backend_get_source (E_BACKEND (backend));
+
+       e_soup_ssl_trust_connect (soup_message, source);
+
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
 
        status_code = soup_session_send_message (soup_session, soup_message);
 
@@ -511,6 +535,8 @@ cal_backend_http_load (ECalBackendHttp *backend,
                g_cancellable_disconnect (cancellable, cancel_id);
 
        if (status_code == SOUP_STATUS_NOT_MODIFIED) {
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+
                /* attempts with ETag can result in 304 status code */
                g_object_unref (soup_message);
                priv->opened = TRUE;
@@ -545,7 +571,7 @@ cal_backend_http_load (ECalBackendHttp *backend,
                        redirected_uri =
                                webcal_to_http_method (newuri, FALSE);
                        success = cal_backend_http_load (
-                               backend, cancellable, redirected_uri, error);
+                               backend, redirected_uri, out_certificate_pem, out_certificate_errors, 
cancellable, error);
                        g_free (redirected_uri);
 
                } else {
@@ -556,6 +582,15 @@ cal_backend_http_load (ECalBackendHttp *backend,
                        success = FALSE;
                }
 
+               if (success) {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+               } else if (status_code == SOUP_STATUS_SSL_FAILED) {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
+                       cal_backend_http_extract_ssl_failed_data (soup_message, out_certificate_pem, 
out_certificate_errors);
+               } else {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+               }
+
                g_object_unref (soup_message);
                return success;
        }
@@ -571,11 +606,21 @@ cal_backend_http_load (ECalBackendHttp *backend,
                        g_set_error (
                                error, SOUP_HTTP_ERROR, status_code,
                                "%s", soup_message->reason_phrase);
+
+               if (status_code == SOUP_STATUS_SSL_FAILED) {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
+                       cal_backend_http_extract_ssl_failed_data (soup_message, out_certificate_pem, 
out_certificate_errors);
+               } else {
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+               }
+
                g_object_unref (soup_message);
                empty_cache (backend);
                return FALSE;
        }
 
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+
        if (priv->store) {
                const gchar *etag;
 
@@ -739,6 +784,8 @@ begin_retrieval_cb (GIOSchedulerJob *job,
                     ECalBackendHttp *backend)
 {
        const gchar *uri;
+       gchar *certificate_pem = NULL;
+       GTlsCertificateFlags certificate_errors = 0;
        GError *error = NULL;
 
        if (!e_backend_get_online (E_BACKEND (backend)))
@@ -752,19 +799,33 @@ begin_retrieval_cb (GIOSchedulerJob *job,
        backend->priv->is_loading = TRUE;
 
        uri = cal_backend_http_ensure_uri (backend);
-       cal_backend_http_load (backend, cancellable, uri, &error);
+       cal_backend_http_load (backend, uri, &certificate_pem, &certificate_errors, cancellable, &error);
+
+       if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+           g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+               GError *local_error = NULL;
+               ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
+
+               if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+                       reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
+               }
+
+               e_backend_credentials_required_sync (E_BACKEND (backend),
+                       reason, certificate_pem, certificate_errors, error, cancellable, &local_error);
 
-       if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                g_clear_error (&error);
-               e_backend_authenticate_sync (
-                       E_BACKEND (backend),
-                       E_SOURCE_AUTHENTICATOR (backend),
-                       cancellable, &error);
+               error = local_error;
        } else if (g_error_matches (error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
+               GError *local_error = NULL;
+
+               e_backend_credentials_required_sync (E_BACKEND (backend), 
E_SOURCE_CREDENTIALS_REASON_REJECTED,
+                       certificate_pem, certificate_errors, error, cancellable, &local_error);
+
                g_clear_error (&error);
-               error = EDC_ERROR (AuthenticationRequired);
+               error = local_error;
        }
 
+       g_free (certificate_pem);
        backend->priv->is_loading = FALSE;
 
        /* Ignore cancellations. */
@@ -848,7 +909,6 @@ e_cal_backend_http_open (ECalBackendSync *backend,
        ECalBackendHttp *cbhttp;
        ECalBackendHttpPrivate *priv;
        ESource *source;
-       ESourceRegistry *registry;
        ESourceWebdav *webdav_extension;
        const gchar *extension_name;
        const gchar *cache_dir;
@@ -866,8 +926,6 @@ e_cal_backend_http_open (ECalBackendSync *backend,
        source = e_backend_get_source (E_BACKEND (backend));
        cache_dir = e_cal_backend_get_cache_dir (E_CAL_BACKEND (backend));
 
-       registry = e_cal_backend_get_registry (E_CAL_BACKEND (backend));
-
        extension_name = E_SOURCE_EXTENSION_WEBDAV_BACKEND;
        webdav_extension = e_source_get_extension (source, extension_name);
 
@@ -902,25 +960,39 @@ e_cal_backend_http_open (ECalBackendSync *backend,
        e_cal_backend_set_writable (E_CAL_BACKEND (backend), FALSE);
 
        if (e_backend_get_online (E_BACKEND (backend))) {
+               gchar *certificate_pem = NULL;
+               GTlsCertificateFlags certificate_errors = 0;
                const gchar *uri;
 
                uri = cal_backend_http_ensure_uri (cbhttp);
 
-               opened = cal_backend_http_load (
-                       cbhttp, cancellable,
-                       uri, &local_error);
+               opened = cal_backend_http_load (cbhttp, uri, &certificate_pem,
+                       &certificate_errors, cancellable, &local_error);
+
+               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED) ||
+                   g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+                       GError *local_error2 = NULL;
+                       ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
 
-               if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+                       if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+                               reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
+                       }
+
+                       e_backend_credentials_required_sync (E_BACKEND (cbhttp), reason, certificate_pem,
+                               certificate_errors, local_error, cancellable, &local_error2);
                        g_clear_error (&local_error);
-                       opened = e_source_registry_authenticate_sync (
-                               registry, source,
-                               E_SOURCE_AUTHENTICATOR (backend),
-                               cancellable, &local_error);
+                       local_error = local_error2;
                } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_FORBIDDEN)) {
+                       GError *local_error2 = NULL;
+
+                       e_backend_credentials_required_sync (E_BACKEND (cbhttp), 
E_SOURCE_CREDENTIALS_REASON_REJECTED,
+                               certificate_pem, certificate_errors, local_error, cancellable, &local_error2);
+
                        g_clear_error (&local_error);
-                       local_error = EDC_ERROR (AuthenticationRequired);
+                       local_error = local_error2;
                }
 
+               g_free (certificate_pem);
 
                if (local_error != NULL)
                        g_propagate_error (perror, g_error_copy (local_error));
@@ -1407,29 +1479,42 @@ e_cal_backend_http_send_objects (ECalBackendSync *backend,
 }
 
 static ESourceAuthenticationResult
-cal_backend_http_try_password_sync (ESourceAuthenticator *authenticator,
-                                    const GString *password,
-                                    GCancellable *cancellable,
-                                    GError **error)
+e_cal_backend_http_authenticate_sync (EBackend *backend,
+                                     const ENamedParameters *credentials,
+                                     gchar **out_certificate_pem,
+                                     GTlsCertificateFlags *out_certificate_errors,
+                                     GCancellable *cancellable,
+                                     GError **error)
 {
-       ECalBackendHttp *backend;
+       ECalBackendHttp *cbhttp;
        ESourceAuthenticationResult result;
-       const gchar *uri;
+       const gchar *uri, *username;
        GError *local_error = NULL;
 
-       backend = E_CAL_BACKEND_HTTP (authenticator);
+       cbhttp = E_CAL_BACKEND_HTTP (backend);
+
+       g_free (cbhttp->priv->username);
+       cbhttp->priv->username = NULL;
 
-       g_free (backend->priv->password);
-       backend->priv->password = g_strdup (password->str);
+       g_free (cbhttp->priv->password);
+       cbhttp->priv->password = g_strdup (e_named_parameters_get (credentials, 
E_SOURCE_CREDENTIAL_PASSWORD));
 
-       uri = cal_backend_http_ensure_uri (backend);
-       cal_backend_http_load (backend, cancellable, uri, &local_error);
+       username = e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME);
+       if (username && *username) {
+               cbhttp->priv->username = g_strdup (username);
+       }
+
+       uri = cal_backend_http_ensure_uri (cbhttp);
+       cal_backend_http_load (cbhttp, uri, out_certificate_pem, out_certificate_errors, cancellable, 
&local_error);
 
        if (local_error == NULL) {
                result = E_SOURCE_AUTHENTICATION_ACCEPTED;
        } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
                result = E_SOURCE_AUTHENTICATION_REJECTED;
                g_clear_error (&local_error);
+       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+               result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
+               g_propagate_error (error, local_error);
        } else {
                result = E_SOURCE_AUTHENTICATION_ERROR;
                g_propagate_error (error, local_error);
@@ -1454,23 +1539,27 @@ static void
 e_cal_backend_http_class_init (ECalBackendHttpClass *class)
 {
        GObjectClass *object_class;
-       ECalBackendClass *backend_class;
+       EBackendClass *backend_class;
+       ECalBackendClass *cal_backend_class;
        ECalBackendSyncClass *sync_class;
 
        g_type_class_add_private (class, sizeof (ECalBackendHttpPrivate));
 
        object_class = (GObjectClass *) class;
-       backend_class = (ECalBackendClass *) class;
+       backend_class = E_BACKEND_CLASS (class);
+       cal_backend_class = (ECalBackendClass *) class;
        sync_class = (ECalBackendSyncClass *) class;
 
        object_class->dispose = e_cal_backend_http_dispose;
        object_class->finalize = e_cal_backend_http_finalize;
        object_class->constructed = e_cal_backend_http_constructed;
 
-       /* Execute one method at a time. */
-       backend_class->use_serial_dispatch_queue = TRUE;
+       backend_class->authenticate_sync = e_cal_backend_http_authenticate_sync;
 
-       backend_class->get_backend_property = e_cal_backend_http_get_backend_property;
+       /* Execute one method at a time. */
+       cal_backend_class->use_serial_dispatch_queue = TRUE;
+       cal_backend_class->get_backend_property = e_cal_backend_http_get_backend_property;
+       cal_backend_class->start_view = e_cal_backend_http_start_view;
 
        sync_class->open_sync = e_cal_backend_http_open;
        sync_class->refresh_sync = e_cal_backend_http_refresh;
@@ -1483,13 +1572,4 @@ e_cal_backend_http_class_init (ECalBackendHttpClass *class)
        sync_class->get_object_list_sync = e_cal_backend_http_get_object_list;
        sync_class->add_timezone_sync = e_cal_backend_http_add_timezone;
        sync_class->get_free_busy_sync = e_cal_backend_http_get_free_busy;
-
-       backend_class->start_view = e_cal_backend_http_start_view;
 }
-
-static void
-e_cal_backend_http_source_authenticator_init (ESourceAuthenticatorInterface *iface)
-{
-       iface->try_password_sync = cal_backend_http_try_password_sync;
-}
-
diff --git a/calendar/libecal/e-cal-client.c b/calendar/libecal/e-cal-client.c
index f139d61..09d115b 100644
--- a/calendar/libecal/e-cal-client.c
+++ b/calendar/libecal/e-cal-client.c
@@ -104,6 +104,7 @@ struct _SignalClosure {
 struct _ConnectClosure {
        ESource *source;
        GCancellable *cancellable;
+       guint32 wait_for_connected_seconds;
 };
 
 struct _RunInThreadClosure {
@@ -1132,6 +1133,33 @@ cal_client_refresh_sync (EClient *client,
        return TRUE;
 }
 
+static gboolean
+cal_client_retrieve_properties_sync (EClient *client,
+                                    GCancellable *cancellable,
+                                    GError **error)
+{
+       ECalClient *cal_client;
+       gchar **properties = NULL;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (E_IS_CAL_CLIENT (client), FALSE);
+
+       cal_client = E_CAL_CLIENT (client);
+
+       e_dbus_calendar_call_retrieve_properties_sync (cal_client->priv->dbus_proxy, &properties, 
cancellable, &local_error);
+
+       cal_client_process_properties (cal_client, properties);
+       g_strfreev (properties);
+
+       if (local_error != NULL) {
+               g_dbus_error_strip_remote_error (local_error);
+               g_propagate_error (error, local_error);
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
 static void
 cal_client_init_in_dbus_thread (GSimpleAsyncResult *simple,
                                 GObject *source_object,
@@ -1534,6 +1562,7 @@ e_cal_client_class_init (ECalClientClass *class)
        client_class->set_backend_property_sync = cal_client_set_backend_property_sync;
        client_class->open_sync = cal_client_open_sync;
        client_class->refresh_sync = cal_client_refresh_sync;
+       client_class->retrieve_properties_sync = cal_client_retrieve_properties_sync;
 
        g_object_class_install_property (
                object_class,
@@ -1612,12 +1641,22 @@ e_cal_client_init (ECalClient *client)
  * e_cal_client_connect_sync:
  * @source: an #ESource
  * @source_type: source type of the calendar
+ * @wait_for_connected_seconds: timeout, in seconds, to wait for the backend to be fully connected
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
  * Creates a new #ECalClient for @source and @source_type.  If an error
  * occurs, the function will set @error and return %FALSE.
  *
+ * The @wait_for_connected_seconds argument had been added since 3.14,
+ * to let the caller decide how long to wait for the backend to fully
+ * connect to its (possibly remote) data store. This is required due
+ * to a change in the authentication process, which is fully asynchronous
+ * and done on the client side, while not every client is supposed to
+ * response to authentication requests. In case the backend will not connect
+ * within the set interval, then it is opened in an offline mode. A special
+ * value -1 can be used to not wait for the connected state at all.
+ *
  * Unlike with e_cal_client_new(), there is no need to call
  * e_client_open_sync() after obtaining the #ECalClient.
  *
@@ -1632,6 +1671,7 @@ e_cal_client_init (ECalClient *client)
 EClient *
 e_cal_client_connect_sync (ESource *source,
                            ECalClientSourceType source_type,
+                          guint32 wait_for_connected_seconds,
                            GCancellable *cancellable,
                            GError **error)
 {
@@ -1661,6 +1701,12 @@ e_cal_client_connect_sync (ESource *source,
                g_strfreev (properties);
        }
 
+       if (!local_error && wait_for_connected_seconds != (guint32) -1) {
+               /* These errors are ignored, the book is left opened in an offline mode. */
+               e_client_wait_for_connected_sync (E_CLIENT (client),
+                       wait_for_connected_seconds, cancellable, NULL);
+       }
+
        if (local_error != NULL) {
                g_dbus_error_strip_remote_error (local_error);
                g_propagate_error (error, local_error);
@@ -1674,6 +1720,23 @@ e_cal_client_connect_sync (ESource *source,
        return E_CLIENT (client);
 }
 
+static void
+cal_client_connect_wait_for_connected_cb (GObject *source_object,
+                                          GAsyncResult *result,
+                                          gpointer user_data)
+{
+       GSimpleAsyncResult *simple;
+
+       simple = G_SIMPLE_ASYNC_RESULT (user_data);
+
+       /* These errors are ignored, the book is left opened in an offline mode. */
+       e_client_wait_for_connected_finish (E_CLIENT (source_object), result, NULL);
+
+       g_simple_async_result_complete (simple);
+
+       g_object_unref (simple);
+}
+
 /* Helper for e_cal_client_connect() */
 static void
 cal_client_connect_open_cb (GObject *source_object,
@@ -1693,6 +1756,24 @@ cal_client_connect_open_cb (GObject *source_object,
        client_object = g_async_result_get_source_object (G_ASYNC_RESULT (simple));
        if (client_object) {
                cal_client_process_properties (E_CAL_CLIENT (client_object), properties);
+
+               if (!local_error) {
+                       ConnectClosure *closure;
+
+                       closure = g_simple_async_result_get_op_res_gpointer (simple);
+                       if (closure->wait_for_connected_seconds != (guint32) -1) {
+                               e_client_wait_for_connected (E_CLIENT (client_object),
+                                       closure->wait_for_connected_seconds,
+                                       closure->cancellable,
+                                       cal_client_connect_wait_for_connected_cb, g_object_ref (simple));
+
+                               g_clear_object (&client_object);
+                               g_object_unref (simple);
+                               g_strfreev (properties);
+                               return;
+                       }
+               }
+
                g_clear_object (&client_object);
        }
 
@@ -1753,6 +1834,7 @@ exit:
  * e_cal_client_connect:
  * @source: an #ESource
  * @source_type: source tpe of the calendar
+ * @wait_for_connected_seconds: timeout, in seconds, to wait for the backend to be fully connected
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
  * @callback: (scope async): a #GAsyncReadyCallback to call when the request
  *            is satisfied
@@ -1760,6 +1842,15 @@ exit:
  *
  * Asynchronously creates a new #ECalClient for @source and @source_type.
  *
+ * The @wait_for_connected_seconds argument had been added since 3.14,
+ * to let the caller decide how long to wait for the backend to fully
+ * connect to its (possibly remote) data store. This is required due
+ * to a change in the authentication process, which is fully asynchronous
+ * and done on the client side, while not every client is supposed to
+ * response to authentication requests. In case the backend will not connect
+ * within the set interval, then it is opened in an offline mode. A special
+ * value -1 can be used to not wait for the connected state at all.
+ *
  * Unlike with e_cal_client_new(), there is no need to call e_client_open()
  * after obtaining the #ECalClient.
  *
@@ -1771,6 +1862,7 @@ exit:
 void
 e_cal_client_connect (ESource *source,
                       ECalClientSourceType source_type,
+                     guint32 wait_for_connected_seconds,
                       GCancellable *cancellable,
                       GAsyncReadyCallback callback,
                       gpointer user_data)
@@ -1793,6 +1885,7 @@ e_cal_client_connect (ESource *source,
 
        closure = g_slice_new0 (ConnectClosure);
        closure->source = g_object_ref (source);
+       closure->wait_for_connected_seconds = wait_for_connected_seconds;
 
        if (G_IS_CANCELLABLE (cancellable))
                closure->cancellable = g_object_ref (cancellable);
diff --git a/calendar/libecal/e-cal-client.h b/calendar/libecal/e-cal-client.h
index a0c2c42..25b4319 100644
--- a/calendar/libecal/e-cal-client.h
+++ b/calendar/libecal/e-cal-client.h
@@ -137,10 +137,12 @@ const gchar *     e_cal_client_error_to_string    (ECalClientError code);
 GType          e_cal_client_get_type           (void) G_GNUC_CONST;
 EClient *      e_cal_client_connect_sync       (ESource *source,
                                                 ECalClientSourceType source_type,
+                                                guint32 wait_for_connected_seconds,
                                                 GCancellable *cancellable,
                                                 GError **error);
 void           e_cal_client_connect            (ESource *source,
                                                 ECalClientSourceType source_type,
+                                                guint32 wait_for_connected_seconds,
                                                 GCancellable *cancellable,
                                                 GAsyncReadyCallback callback,
                                                 gpointer user_data);
diff --git a/calendar/libedata-cal/e-cal-backend.c b/calendar/libedata-cal/e-cal-backend.c
index 5302151..6179986 100644
--- a/calendar/libedata-cal/e-cal-backend.c
+++ b/calendar/libedata-cal/e-cal-backend.c
@@ -706,24 +706,6 @@ cal_backend_constructed (GObject *object)
        }
 }
 
-static gboolean
-cal_backend_authenticate_sync (EBackend *backend,
-                               ESourceAuthenticator *auth,
-                               GCancellable *cancellable,
-                               GError **error)
-{
-       ECalBackend *cal_backend;
-       ESourceRegistry *registry;
-       ESource *source;
-
-       cal_backend = E_CAL_BACKEND (backend);
-       registry = e_cal_backend_get_registry (cal_backend);
-       source = e_backend_get_source (backend);
-
-       return e_source_registry_authenticate_sync (
-               registry, source, auth, cancellable, error);
-}
-
 static void
 cal_backend_prepare_shutdown (EBackend *backend)
 {
@@ -929,7 +911,6 @@ e_cal_backend_class_init (ECalBackendClass *class)
        object_class->constructed = cal_backend_constructed;
 
        backend_class = E_BACKEND_CLASS (class);
-       backend_class->authenticate_sync = cal_backend_authenticate_sync;
        backend_class->prepare_shutdown = cal_backend_prepare_shutdown;
 
        class->get_backend_property = cal_backend_get_backend_property;
diff --git a/calendar/libedata-cal/e-data-cal.c b/calendar/libedata-cal/e-data-cal.c
index ee2b9dd..e291065 100644
--- a/calendar/libedata-cal/e-data-cal.c
+++ b/calendar/libedata-cal/e-data-cal.c
@@ -497,24 +497,20 @@ e_data_cal_create_error_fmt (EDataCalCallStatus status,
        return error;
 }
 
-static void
-data_cal_complete_open_cb (GObject *source_object,
-                           GAsyncResult *result,
-                           gpointer user_data)
+static GPtrArray *
+data_cal_encode_properties (EDBusCalendar *dbus_interface)
 {
-       AsyncContext *async_context = user_data;
-       GError *error = NULL;
+       GPtrArray *properties_array;
 
-       e_cal_backend_open_finish (
-               E_CAL_BACKEND (source_object), result, &error);
+       g_warn_if_fail (E_DBUS_IS_CALENDAR (dbus_interface));
 
-       if (error == NULL) {
-               GPtrArray *properties_array;
+       properties_array = g_ptr_array_new_with_free_func (g_free);
+
+       if (dbus_interface) {
                GParamSpec **properties;
                guint ii, n_properties = 0;
 
-               properties_array = g_ptr_array_new_with_free_func (g_free);
-               properties = g_object_class_list_properties (G_OBJECT_GET_CLASS 
(async_context->dbus_interface), &n_properties);
+               properties = g_object_class_list_properties (G_OBJECT_GET_CLASS (dbus_interface), 
&n_properties);
 
                for (ii = 0; ii < n_properties; ii++) {
                        gboolean can_process =
@@ -533,7 +529,7 @@ data_cal_complete_open_cb (GObject *source_object,
                                GVariant *stored = NULL;
 
                                g_value_init (&value, properties[ii]->value_type);
-                               g_object_get_property ((GObject *) async_context->dbus_interface, 
properties[ii]->name, &value);
+                               g_object_get_property ((GObject *) dbus_interface, properties[ii]->name, 
&value);
 
                                #define WORKOUT(gvl, gvr) \
                                        if (g_type_is_a (properties[ii]->value_type, G_TYPE_ ## gvl)) \
@@ -563,8 +559,47 @@ data_cal_complete_open_cb (GObject *source_object,
                }
 
                g_free (properties);
+       }
+
+       g_ptr_array_add (properties_array, NULL);
+
+       return properties_array;
+}
+
+static gboolean
+data_cal_handle_retrieve_properties_cb (EDBusCalendar *dbus_interface,
+                                       GDBusMethodInvocation *invocation,
+                                       EDataCal *data_cal)
+{
+       GPtrArray *properties_array;
+
+       properties_array = data_cal_encode_properties (dbus_interface);
+
+       e_dbus_calendar_complete_retrieve_properties (
+               dbus_interface,
+               invocation,
+               (const gchar * const *) properties_array->pdata);
 
-               g_ptr_array_add (properties_array, NULL);
+       g_ptr_array_free (properties_array, TRUE);
+
+       return TRUE;
+}
+
+static void
+data_cal_complete_open_cb (GObject *source_object,
+                           GAsyncResult *result,
+                           gpointer user_data)
+{
+       AsyncContext *async_context = user_data;
+       GError *error = NULL;
+
+       e_cal_backend_open_finish (
+               E_CAL_BACKEND (source_object), result, &error);
+
+       if (error == NULL) {
+               GPtrArray *properties_array;
+
+               properties_array = data_cal_encode_properties (async_context->dbus_interface);
 
                e_dbus_calendar_complete_open (
                        async_context->dbus_interface,
@@ -2644,6 +2679,9 @@ e_data_cal_init (EDataCal *data_cal)
                (GDestroyNotify) g_ptr_array_unref);
 
        g_signal_connect (
+               dbus_interface, "handle-retrieve-properties",
+               G_CALLBACK (data_cal_handle_retrieve_properties_cb), data_cal);
+       g_signal_connect (
                dbus_interface, "handle-open",
                G_CALLBACK (data_cal_handle_open_cb), data_cal);
        g_signal_connect (
diff --git a/configure.ac b/configure.ac
index 761fb1e..e25d929 100644
--- a/configure.ac
+++ b/configure.ac
@@ -39,8 +39,8 @@ m4_define([glib_minimum_version], [2.40])
 m4_define([glib_encoded_version], [GLIB_VERSION_2_40])
 
 dnl Keep these two definitions in agreement.
-m4_define([gdk_minimum_version], [3.2])
-m4_define([gdk_encoded_version], [GDK_VERSION_3_2])
+m4_define([gdk_minimum_version], [3.6])
+m4_define([gdk_encoded_version], [GDK_VERSION_3_6])
 
 dnl Keep these two definitions in agreement.
 m4_define([soup_minimum_version], [2.42])
@@ -73,9 +73,9 @@ GLIB_GSETTINGS
 dnl ******************************
 dnl D-Bus versioning
 dnl ******************************
-ADDRESS_BOOK_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.AddressBook8"
-CALENDAR_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.Calendar6"
-SOURCES_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.Sources3"
+ADDRESS_BOOK_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.AddressBook9"
+CALENDAR_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.Calendar7"
+SOURCES_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.Sources4"
 USER_PROMPTER_DBUS_SERVICE_NAME="org.gnome.evolution.dataserver.UserPrompter0"
 
 AC_DEFINE_UNQUOTED(
@@ -106,27 +106,31 @@ AC_SUBST(USER_PROMPTER_DBUS_SERVICE_NAME)
 dnl ******************************
 dnl Libtool versioning
 dnl ******************************
-LIBEDATASERVER_CURRENT=19
+LIBEDATASERVER_CURRENT=20
 LIBEDATASERVER_REVISION=0
 LIBEDATASERVER_AGE=0
 
-LIBECAL_CURRENT=17
+LIBEDATASERVERUI_CURRENT=1
+LIBEDATASERVERUI_REVISION=0
+LIBEDATASERVERUI_AGE=0
+
+LIBECAL_CURRENT=18
 LIBECAL_REVISION=0
 LIBECAL_AGE=0
 
-LIBEDATACAL_CURRENT=26
+LIBEDATACAL_CURRENT=27
 LIBEDATACAL_REVISION=0
 LIBEDATACAL_AGE=0
 
-LIBEDATABOOK_CURRENT=24
+LIBEDATABOOK_CURRENT=25
 LIBEDATABOOK_REVISION=0
 LIBEDATABOOK_AGE=0
 
-LIBEBOOK_CURRENT=18
+LIBEBOOK_CURRENT=19
 LIBEBOOK_REVISION=1
 LIBEBOOK_AGE=3
 
-LIBEBOOK_CONTACTS_CURRENT=0
+LIBEBOOK_CONTACTS_CURRENT=1
 LIBEBOOK_CONTACTS_REVISION=0
 LIBEBOOK_CONTACTS_AGE=0
 
@@ -134,7 +138,7 @@ LIBCAMEL_CURRENT=51
 LIBCAMEL_REVISION=0
 LIBCAMEL_AGE=0
 
-LIBEBACKEND_CURRENT=9
+LIBEBACKEND_CURRENT=10
 LIBEBACKEND_REVISION=0
 LIBEBACKEND_AGE=0
 
@@ -144,6 +148,9 @@ AC_SUBST(EDS_MICRO_VERSION)
 AC_SUBST(LIBEDATASERVER_CURRENT)
 AC_SUBST(LIBEDATASERVER_REVISION)
 AC_SUBST(LIBEDATASERVER_AGE)
+AC_SUBST(LIBEDATASERVERUI_CURRENT)
+AC_SUBST(LIBEDATASERVERUI_REVISION)
+AC_SUBST(LIBEDATASERVERUI_AGE)
 AC_SUBST(LIBECAL_CURRENT)
 AC_SUBST(LIBECAL_REVISION)
 AC_SUBST(LIBECAL_AGE)
@@ -1652,6 +1659,9 @@ AC_SUBST(imagesdir)
 moduledir='${privlibdir}'/registry-modules
 AC_SUBST(moduledir)
 
+credentialmoduledir='${privlibdir}'/credential-modules
+AC_SUBST(credentialmoduledir)
+
 ebook_backenddir='${privlibdir}'/addressbook-backends
 AC_SUBST(ebook_backenddir)
 
@@ -1798,6 +1808,8 @@ libebackend/libebackend.pc
 libedataserver/Makefile
 libedataserver/eds-version.h
 libedataserver/libedataserver.pc
+libedataserverui/Makefile
+libedataserverui/libedataserverui.pc
 modules/Makefile
 modules/cache-reaper/Makefile
 modules/gnome-online-accounts/Makefile
diff --git a/examples/cursor/cursor-data.c b/examples/cursor/cursor-data.c
index 6d217d7..c7fd19b 100644
--- a/examples/cursor/cursor-data.c
+++ b/examples/cursor/cursor-data.c
@@ -43,7 +43,7 @@ cursor_data_source_added (ESourceRegistry *registry,
                return;
 
        /* Open the address book */
-       address_book = (EBookClient *) e_book_client_connect_sync (source, NULL, &error);
+       address_book = (EBookClient *) e_book_client_connect_sync (source, 30, NULL, &error);
        if (!address_book)
                g_error ("Unable to create the test book: %s", error->message);
 
diff --git a/libebackend/Makefile.am b/libebackend/Makefile.am
index 4cef9b0..dd4633f 100644
--- a/libebackend/Makefile.am
+++ b/libebackend/Makefile.am
@@ -55,20 +55,16 @@ libebackend_1_2_la_CPPFLAGS = \
 
 libebackend_1_2_la_SOURCES = \
        $(BUILT_SOURCES) \
-       e-authentication-mediator.c \
-       e-authentication-session.c \
        e-backend.c \
        e-backend-factory.c \
        e-collection-backend.c \
        e-collection-backend-factory.c \
        e-data-factory.c \
        e-dbus-server.c \
-       e-extensible.c \
-       e-extension.c \
        e-oauth2-support.c \
        e-offline-listener.c \
-       e-module.c \
        e-server-side-source.c \
+       e-server-side-source-credentials-provider.c \
        e-soup-auth-bearer.c \
        e-soup-ssl-trust.c \
        e-source-registry-server.c \
@@ -102,8 +98,6 @@ libebackendincludedir = $(privincludedir)/libebackend
 
 libebackendinclude_HEADERS = \
        libebackend.h \
-       e-authentication-mediator.h \
-       e-authentication-session.h \
        e-backend.h \
        e-backend-enums.h \
        e-backend-enumtypes.h \
@@ -112,12 +106,10 @@ libebackendinclude_HEADERS = \
        e-collection-backend-factory.h \
        e-data-factory.h \
        e-dbus-server.h \
-       e-extensible.h \
-       e-extension.h \
        e-oauth2-support.h \
        e-offline-listener.h \
-       e-module.h \
        e-server-side-source.h \
+       e-server-side-source-credentials-provider.h \
        e-soup-auth-bearer.h \
        e-soup-ssl-trust.h \
        e-source-registry-server.h \
diff --git a/libebackend/e-backend-factory.c b/libebackend/e-backend-factory.c
index ec95d26..6786656 100644
--- a/libebackend/e-backend-factory.c
+++ b/libebackend/e-backend-factory.c
@@ -37,8 +37,9 @@
 
 #include <config.h>
 
+#include <libedataserver/libedataserver.h>
+
 #include <libebackend/e-data-factory.h>
-#include "e-module.h"
 
 G_DEFINE_ABSTRACT_TYPE (EBackendFactory, e_backend_factory, E_TYPE_EXTENSION)
 
diff --git a/libebackend/e-backend-factory.h b/libebackend/e-backend-factory.h
index 6fa61ca..6619694 100644
--- a/libebackend/e-backend-factory.h
+++ b/libebackend/e-backend-factory.h
@@ -22,8 +22,8 @@
 #ifndef E_BACKEND_FACTORY_H
 #define E_BACKEND_FACTORY_H
 
+#include <libedataserver/libedataserver.h>
 #include <libebackend/e-backend.h>
-#include <libebackend/e-extension.h>
 
 /* Standard GObject macros */
 #define E_TYPE_BACKEND_FACTORY \
diff --git a/libebackend/e-backend.c b/libebackend/e-backend.c
index a020c4d..4398e76 100644
--- a/libebackend/e-backend.c
+++ b/libebackend/e-backend.c
@@ -50,8 +50,6 @@
 #define G_IS_RESOLVER_ERROR(error, code) \
        (g_error_matches ((error), G_RESOLVER_ERROR, (code)))
 
-typedef struct _AsyncContext AsyncContext;
-
 struct _EBackendPrivate {
        GMutex property_lock;
        ESource *source;
@@ -68,10 +66,9 @@ struct _EBackendPrivate {
 
        GMutex network_monitor_cancellable_lock;
        GCancellable *network_monitor_cancellable;
-};
 
-struct _AsyncContext {
-       ESourceAuthenticator *auth;
+       GMutex authenticate_cancellable_lock;
+       GCancellable *authenticate_cancellable;
 };
 
 enum {
@@ -86,15 +83,6 @@ enum {
 G_DEFINE_ABSTRACT_TYPE (EBackend, e_backend, G_TYPE_OBJECT)
 
 static void
-async_context_free (AsyncContext *async_context)
-{
-       if (async_context->auth != NULL)
-               g_object_unref (async_context->auth);
-
-       g_slice_free (AsyncContext, async_context);
-}
-
-static void
 backend_network_monitor_can_reach_cb (GObject *source_object,
                                       GAsyncResult *result,
                                       gpointer user_data)
@@ -232,6 +220,173 @@ backend_network_changed_cb (GNetworkMonitor *network_monitor,
        backend_update_online_state (backend);
 }
 
+static ESourceAuthenticationResult
+e_backend_authenticate_sync (EBackend *backend,
+                            const ENamedParameters *credentials,
+                            gchar **out_certificate_pem,
+                            GTlsCertificateFlags *out_certificate_errors,
+                            GCancellable *cancellable,
+                            GError **error)
+{
+       EBackendClass *class;
+
+       g_return_val_if_fail (E_IS_BACKEND (backend), E_SOURCE_AUTHENTICATION_ERROR);
+       g_return_val_if_fail (credentials != NULL, E_SOURCE_AUTHENTICATION_ERROR);
+
+       class = E_BACKEND_GET_CLASS (backend);
+       g_return_val_if_fail (class->authenticate_sync != NULL, E_SOURCE_AUTHENTICATION_ERROR);
+
+       return class->authenticate_sync (backend, credentials, out_certificate_pem, out_certificate_errors, 
cancellable, error);
+}
+
+typedef struct _AuthenticateThreadData {
+       EBackend *backend;
+       GCancellable *cancellable;
+       ENamedParameters *credentials;
+} AuthenticateThreadData;
+
+static AuthenticateThreadData *
+authenticate_thread_data_new (EBackend *backend,
+                             GCancellable *cancellable,
+                             const ENamedParameters *credentials)
+{
+       AuthenticateThreadData *data;
+
+       data = g_new0 (AuthenticateThreadData, 1);
+       data->backend = g_object_ref (backend);
+       data->cancellable = g_object_ref (cancellable);
+       data->credentials = credentials ? e_named_parameters_new_clone (credentials) : e_named_parameters_new 
();
+
+       return data;
+}
+
+static void
+authenticate_thread_data_free (AuthenticateThreadData *data)
+{
+       if (data) {
+               g_clear_object (&data->backend);
+               g_clear_object (&data->cancellable);
+               e_named_parameters_free (data->credentials);
+               g_free (data);
+       }
+}
+
+static gpointer
+backend_source_authenticate_thread (gpointer user_data)
+{
+       ESourceAuthenticationResult auth_result;
+       AuthenticateThreadData *thread_data = user_data;
+       gchar *certificate_pem = NULL;
+       GTlsCertificateFlags certificate_errors = 0;
+       GError *local_error = NULL;
+       ESource *source;
+
+       g_return_val_if_fail (thread_data != NULL, NULL);
+
+       source = e_backend_get_source (thread_data->backend);
+
+       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTING);
+
+       /* Update the SSL trust transparently. */
+       if (e_named_parameters_get (thread_data->credentials, E_SOURCE_CREDENTIAL_SSL_TRUST) &&
+           e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND)) {
+               ESourceWebdav *webdav_extension;
+
+               webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
+               e_source_webdav_set_ssl_trust (webdav_extension,
+                       e_named_parameters_get (thread_data->credentials, E_SOURCE_CREDENTIAL_SSL_TRUST));
+       }
+
+       auth_result = e_backend_authenticate_sync (thread_data->backend, thread_data->credentials,
+               &certificate_pem, &certificate_errors, thread_data->cancellable, &local_error);
+
+       if (!g_cancellable_is_cancelled (thread_data->cancellable)) {
+               ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_ERROR;
+
+               switch (auth_result) {
+               case E_SOURCE_AUTHENTICATION_ERROR:
+                       reason = E_SOURCE_CREDENTIALS_REASON_ERROR;
+                       break;
+               case E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED:
+                       reason = E_SOURCE_CREDENTIALS_REASON_SSL_FAILED;
+                       break;
+               case E_SOURCE_AUTHENTICATION_ACCEPTED:
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_CONNECTED);
+                       break;
+               case E_SOURCE_AUTHENTICATION_REQUIRED:
+                       reason = E_SOURCE_CREDENTIALS_REASON_REQUIRED;
+                       break;
+               case E_SOURCE_AUTHENTICATION_REJECTED:
+                       reason = E_SOURCE_CREDENTIALS_REASON_REJECTED;
+                       break;
+               }
+
+               if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
+                       const gchar *username = e_named_parameters_get (thread_data->credentials, 
E_SOURCE_CREDENTIAL_USERNAME);
+                       gboolean call_write = FALSE;
+
+                       if (username && *username && e_source_has_extension (source, 
E_SOURCE_EXTENSION_AUTHENTICATION)) {
+                               ESourceAuthentication *extension_authentication = e_source_get_extension 
(source, E_SOURCE_EXTENSION_AUTHENTICATION);
+
+                               if (g_strcmp0 (username, e_source_authentication_get_user 
(extension_authentication)) != 0) {
+                                       e_source_authentication_set_user (extension_authentication, username);
+                                       call_write = TRUE;
+                               }
+                       }
+
+                       if (username && *username && e_source_has_extension (source, 
E_SOURCE_EXTENSION_COLLECTION)) {
+                               ESourceCollection *extension_collection = e_source_get_extension (source, 
E_SOURCE_EXTENSION_COLLECTION);
+
+                               if (g_strcmp0 (username, e_source_collection_get_identity 
(extension_collection)) != 0) {
+                                       e_source_collection_set_identity (extension_collection, username);
+                                       call_write = TRUE;
+                               }
+                       }
+
+                       if (call_write) {
+                               GError *local_error2 = NULL;
+
+                               if (!e_source_write_sync (source, thread_data->cancellable, &local_error2)) {
+                                       g_warning ("%s: Failed to store changed user name: %s", G_STRFUNC, 
local_error2 ? local_error2->message : "Unknown error");
+                               }
+
+                               g_clear_error (&local_error2);
+                       }
+               } else {
+                       GError *local_error2 = NULL;
+
+                       e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+
+                       if (!e_source_invoke_credentials_required_sync (source, reason, certificate_pem, 
certificate_errors,
+                               local_error, thread_data->cancellable, &local_error2)) {
+                               g_warning ("%s: Failed to invoke credentials required: %s", G_STRFUNC, 
local_error2 ? local_error2->message : "Unknown error");
+                       }
+
+                       g_clear_error (&local_error2);
+               }
+       } else {
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+       }
+
+       g_free (certificate_pem);
+       g_clear_error (&local_error);
+
+       authenticate_thread_data_free (thread_data);
+
+       return NULL;
+}
+
+static void
+backend_source_authenticate_cb (ESource *source,
+                               const ENamedParameters *credentials,
+                               EBackend *backend)
+{
+       g_return_if_fail (E_IS_BACKEND (backend));
+       g_return_if_fail (credentials != NULL);
+
+       e_backend_schedule_authenticate (backend, credentials);
+}
+
 static void
 backend_set_source (EBackend *backend,
                     ESource *source)
@@ -240,6 +395,8 @@ backend_set_source (EBackend *backend,
        g_return_if_fail (backend->priv->source == NULL);
 
        backend->priv->source = g_object_ref (source);
+
+       g_signal_connect (backend->priv->source, "authenticate", G_CALLBACK (backend_source_authenticate_cb), 
backend);
 }
 
 static void
@@ -337,6 +494,17 @@ backend_dispose (GObject *object)
                priv->update_online_state = NULL;
        }
 
+       if (priv->source) {
+               g_signal_handlers_disconnect_by_func (priv->source, backend_source_authenticate_cb, object);
+       }
+
+       g_mutex_lock (&priv->authenticate_cancellable_lock);
+       if (priv->authenticate_cancellable) {
+               g_cancellable_cancel (priv->authenticate_cancellable);
+               g_clear_object (&priv->authenticate_cancellable);
+       }
+       g_mutex_unlock (&priv->authenticate_cancellable_lock);
+
        g_clear_object (&priv->source);
        g_clear_object (&priv->prompter);
        g_clear_object (&priv->connectable);
@@ -357,6 +525,7 @@ backend_finalize (GObject *object)
        g_mutex_clear (&priv->property_lock);
        g_mutex_clear (&priv->update_online_state_lock);
        g_mutex_clear (&priv->network_monitor_cancellable_lock);
+       g_mutex_clear (&priv->authenticate_cancellable_lock);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_backend_parent_class)->finalize (object);
@@ -390,86 +559,6 @@ backend_constructed (GObject *object)
        }
 }
 
-static void
-backend_authenticate_thread (GSimpleAsyncResult *simple,
-                             GObject *object,
-                             GCancellable *cancellable)
-{
-       AsyncContext *async_context;
-       GError *error = NULL;
-
-       async_context = g_simple_async_result_get_op_res_gpointer (simple);
-
-       e_backend_authenticate_sync (
-               E_BACKEND (object),
-               async_context->auth,
-               cancellable, &error);
-
-       if (error != NULL)
-               g_simple_async_result_take_error (simple, error);
-}
-
-static gboolean
-backend_authenticate_sync (EBackend *backend,
-                           ESourceAuthenticator *auth,
-                           GCancellable *cancellable,
-                           GError **error)
-{
-       g_set_error (
-               error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
-               _("%s does not support authentication"),
-               G_OBJECT_TYPE_NAME (backend));
-
-       return FALSE;
-}
-
-static void
-backend_authenticate (EBackend *backend,
-                      ESourceAuthenticator *auth,
-                      GCancellable *cancellable,
-                      GAsyncReadyCallback callback,
-                      gpointer user_data)
-{
-       GSimpleAsyncResult *simple;
-       AsyncContext *async_context;
-
-       async_context = g_slice_new0 (AsyncContext);
-       async_context->auth = g_object_ref (auth);
-
-       simple = g_simple_async_result_new (
-               G_OBJECT (backend), callback,
-               user_data, backend_authenticate);
-
-       g_simple_async_result_set_check_cancellable (simple, cancellable);
-
-       g_simple_async_result_set_op_res_gpointer (
-               simple, async_context, (GDestroyNotify) async_context_free);
-
-       g_simple_async_result_run_in_thread (
-               simple, backend_authenticate_thread,
-               G_PRIORITY_DEFAULT, cancellable);
-
-       g_object_unref (simple);
-}
-
-static gboolean
-backend_authenticate_finish (EBackend *backend,
-                             GAsyncResult *result,
-                             GError **error)
-{
-       GSimpleAsyncResult *simple;
-
-       g_return_val_if_fail (
-               g_simple_async_result_is_valid (
-               result, G_OBJECT (backend),
-               backend_authenticate), FALSE);
-
-       simple = G_SIMPLE_ASYNC_RESULT (result);
-
-       /* Assume success unless a GError is set. */
-       return !g_simple_async_result_propagate_error (simple, error);
-}
-
 static gboolean
 backend_get_destination_address (EBackend *backend,
                                  gchar **host,
@@ -499,9 +588,6 @@ e_backend_class_init (EBackendClass *class)
        object_class->finalize = backend_finalize;
        object_class->constructed = backend_constructed;
 
-       class->authenticate_sync = backend_authenticate_sync;
-       class->authenticate = backend_authenticate;
-       class->authenticate_finish = backend_authenticate_finish;
        class->get_destination_address = backend_get_destination_address;
        class->prepare_shutdown = backend_prepare_shutdown;
 
@@ -577,6 +663,9 @@ e_backend_init (EBackend *backend)
        g_mutex_init (&backend->priv->property_lock);
        g_mutex_init (&backend->priv->update_online_state_lock);
        g_mutex_init (&backend->priv->network_monitor_cancellable_lock);
+       g_mutex_init (&backend->priv->authenticate_cancellable_lock);
+
+       backend->priv->authenticate_cancellable = NULL;
 
        /* Configure network monitoring. */
 
@@ -646,6 +735,9 @@ e_backend_set_online (EBackend *backend,
        g_mutex_unlock (&backend->priv->network_monitor_cancellable_lock);
 
        g_object_notify (G_OBJECT (backend), "online");
+
+       if (!backend->priv->online && backend->priv->source)
+               e_source_set_connection_status (backend->priv->source, 
E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
 }
 
 /**
@@ -763,112 +855,256 @@ e_backend_ref_main_context (EBackend *backend)
 }
 
 /**
- * e_backend_authenticate_sync:
+ * e_backend_credentials_required_sync:
  * @backend: an #EBackend
- * @auth: an #ESourceAuthenticator
+ * @reason: an #ESourceCredentialsReason, why the credentials are required
+ * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
+ * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
+ * @op_error: (allow none): a #GError with a description of the previous credentials error, or %NULL
  * @cancellable: optional #GCancellable object, or %NULL
  * @error: return location for a #GError, or %NULL
  *
- * Convenience function providing a consistent authentication interface
- * for backends running in either the registry service itself or a client
- * process communicating with the registry service over D-Bus.
+ * Synchronously lets the clients know that the backned requires credentials to be
+ * properly opened. It's a proxy function for e_source_invoke_credentials_required_sync(),
+ * where can be found more information about actual parameters meaning.
  *
- * Authenticates @backend's #EBackend:source, using @auth to handle
- * authentication attempts.  The @backend and @auth arguments may be one
- * and the same if @backend implements the #ESourceAuthenticator interface.
- * The operation loops until authentication is successful or the user aborts
- * further authentication attempts.  If an error occurs, the function will
- * set @error and return %FALSE.
+ * The provided credentials are received through EBackend::authenticate_sync()
+ * method asynchronously.
  *
- * Returns: %TRUE on success, %FALSE on failure
+ * If an error occurs, the function sets @error and returns %FALSE.
  *
- * Since: 3.6
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
  **/
 gboolean
-e_backend_authenticate_sync (EBackend *backend,
-                             ESourceAuthenticator *auth,
-                             GCancellable *cancellable,
-                             GError **error)
+e_backend_credentials_required_sync (EBackend *backend,
+                                    ESourceCredentialsReason reason,
+                                    const gchar *certificate_pem,
+                                    GTlsCertificateFlags certificate_errors,
+                                    const GError *op_error,
+                                    GCancellable *cancellable,
+                                    GError **error)
 {
-       EBackendClass *class;
+       ESource *source;
 
        g_return_val_if_fail (E_IS_BACKEND (backend), FALSE);
-       g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth), FALSE);
 
-       class = E_BACKEND_GET_CLASS (backend);
-       g_return_val_if_fail (class->authenticate_sync != NULL, FALSE);
+       source = e_backend_get_source (backend);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
 
-       return class->authenticate_sync (backend, auth, cancellable, error);
+       return e_source_invoke_credentials_required_sync (source,
+               reason, certificate_pem, certificate_errors, op_error, cancellable, error);
+}
+
+typedef struct _CredentialsRequiredData {
+       ESourceCredentialsReason reason;
+       gchar *certificate_pem;
+       GTlsCertificateFlags certificate_errors;
+       GError *op_error;
+} CredentialsRequiredData;
+
+static void
+credentials_required_data_free (gpointer ptr)
+{
+       CredentialsRequiredData *data = ptr;
+
+       if (data) {
+               g_free (data->certificate_pem);
+               g_clear_error (&data->op_error);
+               g_free (data);
+       }
+}
+
+static void
+backend_credentials_required_thread (GTask *task,
+                                    gpointer source_object,
+                                    gpointer task_data,
+                                    GCancellable *cancellable)
+{
+       CredentialsRequiredData *data = task_data;
+       gboolean success;
+       GError *local_error = NULL;
+
+       success = e_backend_credentials_required_sync (
+               E_BACKEND (source_object), data->reason, data->certificate_pem,
+               data->certificate_errors, data->op_error,
+               cancellable, &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
 }
 
 /**
- * e_backend_authenticate:
+ * e_backend_credentials_required:
  * @backend: an #EBackend
- * @auth: an #ESourceAuthenticator
+ * @reason: an #ESourceCredentialsReason, why the credentials are required
+ * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
+ * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
+ * @op_error: (allow none): a #GError with a description of the previous credentials error, or %NULL
  * @cancellable: optional #GCancellable object, or %NULL
- * @callback: a #GAsyncReadyCallback to call when the request is satisfied
- * @user_data: data to pass to the callback function
- *
- * Convenience function providing a consistent authentication interface
- * for backends running in either the registry service itself or a client
- * process communicating with the registry service over D-Bus.
+ * @error: return location for a #GError, or %NULL
  *
- * Asynchronously authenticates @backend's #EBackend:source, using @auth
- * to handle authentication attempts.  The @backend and @auth arguments may
- * be one and the same if @backend implements the #ESourceAuthenticator
- * interface.  The operation loops until authentication is succesful or the
- * user aborts further authentication attempts.
+ * Asynchronously calls the e_backend_credentials_required_sync() on the @backend,
+ * to inform clients that credentials are required.
  *
- * When the operation is finished, @callback will be called.  You can then
- * call e_backend_authenticate_finish() to get the result of the operation.
+ * When the operation is finished, @callback will be called. You can then
+ * call e_backend_credentials_required_finish() to get the result of the operation.
  *
- * Since: 3.6
+ * Since: 3.14
  **/
 void
-e_backend_authenticate (EBackend *backend,
-                        ESourceAuthenticator *auth,
-                        GCancellable *cancellable,
-                        GAsyncReadyCallback callback,
-                        gpointer user_data)
+e_backend_credentials_required (EBackend *backend,
+                               ESourceCredentialsReason reason,
+                               const gchar *certificate_pem,
+                               GTlsCertificateFlags certificate_errors,
+                               const GError *op_error,
+                               GCancellable *cancellable,
+                               GAsyncReadyCallback callback,
+                               gpointer user_data)
 {
-       EBackendClass *class;
+       CredentialsRequiredData *data;
+       GTask *task;
 
        g_return_if_fail (E_IS_BACKEND (backend));
-       g_return_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth));
 
-       class = E_BACKEND_GET_CLASS (backend);
-       g_return_if_fail (class->authenticate != NULL);
+       data = g_new0 (CredentialsRequiredData, 1);
+       data->reason = reason;
+       data->certificate_pem = g_strdup (certificate_pem);
+       data->certificate_errors = certificate_errors;
+       data->op_error = op_error ? g_error_copy (op_error) : NULL;
+
+       task = g_task_new (backend, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_backend_credentials_required);
+       g_task_set_task_data (task, data, credentials_required_data_free);
 
-       class->authenticate (backend, auth, cancellable, callback, user_data);
+       g_task_run_in_thread (task, backend_credentials_required_thread);
+
+       g_object_unref (task);
 }
 
 /**
- * e_backend_authenticate_finish:
+ * e_backend_credentials_required_finish:
  * @backend: an #EBackend
  * @result: a #GAsyncResult
  * @error: return location for a #GError, or %NULL
  *
- * Finishes the operation started with e_backend_authenticate().  If
- * an error occurred, the function will set @error and return %FALSE.
+ * Finishes the operation started with e_backend_credentials_required().
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
  *
- * Returns: %TRUE on success, %FALSE on failure
+ * Returns: %TRUE on success, %FALSE on error
  *
- * Since: 3.6
+ * Since: 3.14
  **/
 gboolean
-e_backend_authenticate_finish (EBackend *backend,
-                               GAsyncResult *result,
-                               GError **error)
+e_backend_credentials_required_finish (EBackend *backend,
+                                      GAsyncResult *result,
+                                      GError **error)
 {
-       EBackendClass *class;
-
        g_return_val_if_fail (E_IS_BACKEND (backend), FALSE);
-       g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, backend), FALSE);
 
-       class = E_BACKEND_GET_CLASS (backend);
-       g_return_val_if_fail (class->authenticate_finish != NULL, FALSE);
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_backend_credentials_required), FALSE);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+backend_scheduled_credentials_required_done_cb (GObject *source_object,
+                                               GAsyncResult *result,
+                                               gpointer user_data)
+{
+       GError *error = NULL;
+       gchar *who_calls = user_data;
+
+       g_return_if_fail (E_IS_BACKEND (source_object));
+
+       if (!e_backend_credentials_required_finish (E_BACKEND (source_object), result, &error) &&
+           !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_warning ("%s: Failed to invoke credentials required: %s", who_calls ? who_calls : G_STRFUNC,
+                       error ? error->message : "Unknown error");
+       }
+
+       g_clear_error (&error);
+       g_free (who_calls);
+}
+
+/**
+ * e_backend_schedule_credentials_required:
+ * @backend: an #EBackend
+ * @reason: an #ESourceCredentialsReason, why the credentials are required
+ * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
+ * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
+ * @op_error: (allow none): a #GError with a description of the previous credentials error, or %NULL
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @who_calls: (allow none): an identification who calls this
+ *
+ * Asynchronously invokes e_backend_credentials_required(), but installs its
+ * own callback which only prints a runtime warning on the console when
+ * the call fails. The @who_calls is a prefix of the console message.
+ * This is useful when the caller just wants to start the operation
+ * without having actual place where to show the operation result.
+ *
+ * Since: 3.14
+ **/
+void
+e_backend_schedule_credentials_required (EBackend *backend,
+                                        ESourceCredentialsReason reason,
+                                        const gchar *certificate_pem,
+                                        GTlsCertificateFlags certificate_errors,
+                                        const GError *op_error,
+                                        GCancellable *cancellable,
+                                        const gchar *who_calls)
+{
+       g_return_if_fail (E_IS_BACKEND (backend));
+
+       e_backend_credentials_required (backend, reason, certificate_pem, certificate_errors,
+               op_error, cancellable, backend_scheduled_credentials_required_done_cb, g_strdup (who_calls));
+}
+
+/**
+ * e_backend_schedule_authenticate:
+ * @backend: an #EBackend
+ * @credentials: (allow none): a credentials to use to authenticate, or %NULL
+ *
+ * Schedules a new authenticate session, cancelling any previously run.
+ * This is usually done automatically, when an 'authenticate' signal is
+ * received for the associated #ESource. With %NULL @credentials an attempt
+ * without it is run.
+ *
+ * Since: 3.14
+ **/
+void
+e_backend_schedule_authenticate        (EBackend *backend,
+                                const ENamedParameters *credentials)
+{
+       GCancellable *cancellable;
+       AuthenticateThreadData *thread_data;
+
+       g_return_if_fail (E_IS_BACKEND (backend));
+
+       g_mutex_lock (&backend->priv->authenticate_cancellable_lock);
+       if (backend->priv->authenticate_cancellable) {
+               g_cancellable_cancel (backend->priv->authenticate_cancellable);
+               g_clear_object (&backend->priv->authenticate_cancellable);
+       }
+
+       backend->priv->authenticate_cancellable = g_cancellable_new ();
+       cancellable = g_object_ref (backend->priv->authenticate_cancellable);
+
+       g_mutex_unlock (&backend->priv->authenticate_cancellable_lock);
+
+       thread_data = authenticate_thread_data_new (backend, cancellable, credentials);
+
+       g_thread_unref (g_thread_new (NULL, backend_source_authenticate_thread, thread_data));
 
-       return class->authenticate_finish (backend, result, error);
+       g_clear_object (&cancellable);
 }
 
 /**
diff --git a/libebackend/e-backend.h b/libebackend/e-backend.h
index 4859fb1..bed359a 100644
--- a/libebackend/e-backend.h
+++ b/libebackend/e-backend.h
@@ -83,25 +83,20 @@ struct _EBackendClass {
 
        /*< public >*/
        /* Methods */
-       gboolean        (*authenticate_sync)    (EBackend *backend,
-                                                ESourceAuthenticator *auth,
-                                                GCancellable *cancellable,
-                                                GError **error);
-       void            (*authenticate)         (EBackend *backend,
-                                                ESourceAuthenticator *auth,
-                                                GCancellable *cancellable,
-                                                GAsyncReadyCallback callback,
-                                                gpointer user_data);
-       gboolean        (*authenticate_finish)  (EBackend *backend,
-                                                GAsyncResult *result,
-                                                GError **error);
-
        gboolean        (*get_destination_address)
                                                (EBackend *backend,
                                                 gchar **host,
                                                 guint16 *port);
        void            (*prepare_shutdown)     (EBackend *backend);
 
+       ESourceAuthenticationResult
+                       (*authenticate_sync)    (EBackend *backend,
+                                                const ENamedParameters *credentials,
+                                                gchar **out_certificate_pem,
+                                                GTlsCertificateFlags *out_certificate_errors,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
        /*< private >*/
        gpointer reserved[11];
 };
@@ -116,18 +111,36 @@ GSocketConnectable *
 void           e_backend_set_connectable       (EBackend *backend,
                                                 GSocketConnectable *connectable);
 GMainContext * e_backend_ref_main_context      (EBackend *backend);
-gboolean       e_backend_authenticate_sync     (EBackend *backend,
-                                                ESourceAuthenticator *auth,
+gboolean       e_backend_credentials_required_sync
+                                               (EBackend *backend,
+                                                ESourceCredentialsReason reason,
+                                                const gchar *certificate_pem,
+                                                GTlsCertificateFlags certificate_errors,
+                                                const GError *op_error,
                                                 GCancellable *cancellable,
                                                 GError **error);
-void           e_backend_authenticate          (EBackend *backend,
-                                                ESourceAuthenticator *auth,
+void           e_backend_credentials_required  (EBackend *backend,
+                                                ESourceCredentialsReason reason,
+                                                const gchar *certificate_pem,
+                                                GTlsCertificateFlags certificate_errors,
+                                                const GError *op_error,
                                                 GCancellable *cancellable,
                                                 GAsyncReadyCallback callback,
                                                 gpointer user_data);
-gboolean       e_backend_authenticate_finish   (EBackend *backend,
+gboolean       e_backend_credentials_required_finish
+                                               (EBackend *backend,
                                                 GAsyncResult *result,
                                                 GError **error);
+void           e_backend_schedule_credentials_required
+                                               (EBackend *backend,
+                                                ESourceCredentialsReason reason,
+                                                const gchar *certificate_pem,
+                                                GTlsCertificateFlags certificate_errors,
+                                                const GError *op_error,
+                                                GCancellable *cancellable,
+                                                const gchar *who_calls);
+void           e_backend_schedule_authenticate (EBackend *backend,
+                                                const ENamedParameters *credentials);
 struct _EUserPrompter *
                e_backend_get_user_prompter     (EBackend *backend);
 ETrustPromptResponse
diff --git a/libebackend/e-collection-backend.c b/libebackend/e-collection-backend.c
index 1fdb2f1..0134460 100644
--- a/libebackend/e-collection-backend.c
+++ b/libebackend/e-collection-backend.c
@@ -787,36 +787,6 @@ collection_backend_constructed (GObject *object)
                (GDestroyNotify) g_object_unref);
 }
 
-static gboolean
-collection_backend_authenticate_sync (EBackend *backend,
-                                      ESourceAuthenticator *authenticator,
-                                      GCancellable *cancellable,
-                                      GError **error)
-{
-       ECollectionBackend *collection_backend;
-       ESourceRegistryServer *server;
-       EAuthenticationSession *session;
-       ESource *source;
-       const gchar *source_uid;
-       gboolean success;
-
-       source = e_backend_get_source (backend);
-       source_uid = e_source_get_uid (source);
-
-       collection_backend = E_COLLECTION_BACKEND (backend);
-       server = e_collection_backend_ref_server (collection_backend);
-       session = e_source_registry_server_new_auth_session (
-               server, authenticator, source_uid);
-
-       success = e_source_registry_server_authenticate_sync (
-               server, session, cancellable, error);
-
-       g_object_unref (session);
-       g_object_unref (server);
-
-       return success;
-}
-
 static void
 collection_backend_populate (ECollectionBackend *backend)
 {
@@ -875,12 +845,6 @@ collection_backend_child_added (ECollectionBackend *backend,
        e_server_side_source_set_removable (
                E_SERVER_SIDE_SOURCE (child_source), FALSE);
 
-       /* Collection children inherit the authentication session type. */
-       g_object_bind_property (
-               collection_source, "auth-session-type",
-               child_source, "auth-session-type",
-               G_BINDING_SYNC_CREATE);
-
        /* Collection children inherit OAuth 2.0 support if available. */
        g_object_bind_property (
                collection_source, "oauth2-support",
@@ -1017,7 +981,6 @@ static void
 e_collection_backend_class_init (ECollectionBackendClass *class)
 {
        GObjectClass *object_class;
-       EBackendClass *backend_class;
 
        g_type_class_add_private (class, sizeof (ECollectionBackendPrivate));
 
@@ -1028,9 +991,6 @@ e_collection_backend_class_init (ECollectionBackendClass *class)
        object_class->finalize = collection_backend_finalize;
        object_class->constructed = collection_backend_constructed;
 
-       backend_class = E_BACKEND_CLASS (class);
-       backend_class->authenticate_sync = collection_backend_authenticate_sync;
-
        class->populate = collection_backend_populate;
        class->dup_resource_id = collection_backend_dup_resource_id;
        class->child_added = collection_backend_child_added;
@@ -1726,3 +1686,74 @@ e_collection_backend_delete_resource_finish (ECollectionBackend *backend,
        return class->delete_resource_finish (backend, result, error);
 }
 
+static void
+collection_backend_child_authenticate_done_cb (GObject *source_object,
+                                              GAsyncResult *result,
+                                              gpointer user_data)
+{
+       ESource *source;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_SOURCE (source_object));
+
+       source = E_SOURCE (source_object);
+
+       if (!e_source_invoke_authenticate_finish (source, result, &error) &&
+           !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_warning ("%s: Failed to invoke authenticate for '%s': %s", G_STRFUNC,
+                       e_source_get_uid (source), error ? error->message : "Unknown error");
+       }
+
+       g_clear_error (&error);
+}
+
+/**
+ * e_collection_backend_authenticate_children:
+ * @backend: an #ECollectionBackend
+ * @credentials: credentials to authenticate with
+ *
+ * Authenticates all enabled children sources with the given @crendetials.
+ * This is usually called when the collection source successfully used
+ * the @credentials to connect to the (possibly) remote data store, to
+ * open the childern too. Already connected child sources are skipped.
+ *
+ * Since: 3.14
+ **/
+void
+e_collection_backend_authenticate_children (ECollectionBackend *backend,
+                                           const ENamedParameters *credentials)
+{
+       ESource *master_source, *child, *cred_source;
+       ESourceRegistryServer *registry_server;
+       ESourceCredentialsProvider *credentials_provider;
+       GList *sources, *link;
+
+       g_return_if_fail (E_IS_COLLECTION_BACKEND (backend));
+
+       master_source = e_backend_get_source (E_BACKEND (backend));
+       g_return_if_fail (master_source != NULL);
+
+       registry_server = e_collection_backend_ref_server (backend);
+       g_return_if_fail (registry_server != NULL);
+
+       credentials_provider = e_source_registry_server_ref_credentials_provider (registry_server);
+       sources = e_source_registry_server_list_sources (registry_server, NULL);
+       for (link = sources; link; link = g_list_next (link)) {
+               child = link->data;
+
+               if (child && !e_source_equal (child, master_source) && e_source_get_enabled (child) && (
+                   e_source_get_connection_status (child) == E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS 
||
+                   e_source_get_connection_status (child) == E_SOURCE_CONNECTION_STATUS_DISCONNECTED)) {
+                       cred_source = e_source_credentials_provider_ref_credentials_source 
(credentials_provider, child);
+
+                       if (cred_source && e_source_equal (cred_source, master_source)) {
+                               e_source_invoke_authenticate (child, credentials, NULL, 
collection_backend_child_authenticate_done_cb, NULL);
+                       }
+
+                       g_clear_object (&cred_source);
+               }
+       }
+
+       g_clear_object (&credentials_provider);
+       g_clear_object (&registry_server);
+}
diff --git a/libebackend/e-collection-backend.h b/libebackend/e-collection-backend.h
index 90bc5bd..adb44bb 100644
--- a/libebackend/e-collection-backend.h
+++ b/libebackend/e-collection-backend.h
@@ -160,6 +160,9 @@ gboolean    e_collection_backend_delete_resource_finish
                                                (ECollectionBackend *backend,
                                                 GAsyncResult *result,
                                                 GError **error);
+void           e_collection_backend_authenticate_children
+                                               (ECollectionBackend *backend,
+                                                const ENamedParameters *credentials);
 
 G_END_DECLS
 
diff --git a/libebackend/e-data-factory.c b/libebackend/e-data-factory.c
index 0ef200f..e21d741 100644
--- a/libebackend/e-data-factory.c
+++ b/libebackend/e-data-factory.c
@@ -26,7 +26,8 @@
 #include <config.h>
 #include <glib/gi18n-lib.h>
 
-#include <libebackend/e-extensible.h>
+#include <libedataserver/libedataserver.h>
+
 #include <libebackend/e-backend-factory.h>
 #include <libebackend/e-dbus-server.h>
 
diff --git a/libebackend/e-dbus-server.c b/libebackend/e-dbus-server.c
index 511bf9e..ea5bdc4 100644
--- a/libebackend/e-dbus-server.c
+++ b/libebackend/e-dbus-server.c
@@ -31,8 +31,6 @@
 
 #include <libedataserver/libedataserver.h>
 
-#include <libebackend/e-module.h>
-#include <libebackend/e-extensible.h>
 #include <libebackend/e-backend-enumtypes.h>
 
 #define E_DBUS_SERVER_GET_PRIVATE(obj) \
diff --git a/libebackend/e-server-side-source-credentials-provider.c 
b/libebackend/e-server-side-source-credentials-provider.c
new file mode 100644
index 0000000..ce287e7
--- /dev/null
+++ b/libebackend/e-server-side-source-credentials-provider.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-server-side-source-credentials-provider.h"
+
+struct _EServerSideSourceCredentialsProviderPrivate {
+       gboolean dummy;
+};
+
+G_DEFINE_TYPE (EServerSideSourceCredentialsProvider, e_server_side_source_credentials_provider, 
E_TYPE_SOURCE_CREDENTIALS_PROVIDER)
+
+static ESource *
+server_side_source_credentials_provider_ref_source (ESourceCredentialsProvider *provider,
+                                                   const gchar *uid)
+{
+       ESource *source;
+       GObject *registry;
+
+       g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER (provider), NULL);
+       g_return_val_if_fail (uid, NULL);
+
+       registry = e_source_credentials_provider_ref_registry (provider);
+       if (registry) {
+               g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (registry), NULL);
+
+               source = e_source_registry_server_ref_source (E_SOURCE_REGISTRY_SERVER (registry), uid);
+       }
+
+       g_clear_object (&registry);
+
+       return source;
+}
+
+static void
+e_server_side_source_credentials_provider_class_init (EServerSideSourceCredentialsProviderClass *class)
+{
+       ESourceCredentialsProviderClass *provider_class;
+
+       g_type_class_add_private (class, sizeof (EServerSideSourceCredentialsProviderPrivate));
+
+       provider_class = E_SOURCE_CREDENTIALS_PROVIDER_CLASS (class);
+       provider_class->ref_source = server_side_source_credentials_provider_ref_source;
+}
+
+static void
+e_server_side_source_credentials_provider_init (EServerSideSourceCredentialsProvider *provider)
+{
+       provider->priv = G_TYPE_INSTANCE_GET_PRIVATE (provider, 
E_TYPE_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER, EServerSideSourceCredentialsProviderPrivate);
+}
+
+/**
+ * e_server_side_source_credentials_provider_new:
+ * @registry: an #ESourceRegistryServer
+ *
+ * Creates a new #EServerSideSourceCredentialsProvider, which is meant to abstract
+ * credential management for #ESource<!-- -->-s.
+ *
+ * Returns: (transfer full): a new #EServerSideSourceCredentialsProvider
+ *
+ * Since: 3.14
+ **/
+ESourceCredentialsProvider *
+e_server_side_source_credentials_provider_new (ESourceRegistryServer *registry)
+{
+       g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (registry), NULL);
+
+       return g_object_new (E_TYPE_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER,
+               "registry", registry,
+               NULL);
+}
diff --git a/libebackend/e-server-side-source-credentials-provider.h 
b/libebackend/e-server-side-source-credentials-provider.h
new file mode 100644
index 0000000..e830447
--- /dev/null
+++ b/libebackend/e-server-side-source-credentials-provider.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined (__LIBEBACKEND_H_INSIDE__) && !defined (LIBEBACKEND_COMPILATION)
+#error "Only <libebackend/libebackend.h> should be included directly."
+#endif
+
+#ifndef E_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER_H
+#define E_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include <libedataserver/libedataserver.h>
+#include <libebackend/e-source-registry-server.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER \
+       (e_server_side_source_credentials_provider_get_type ())
+#define E_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER, EServerSideSourceCredentialsProvider))
+#define E_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER, EServerSideSourceCredentialsProviderClass))
+#define E_IS_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER))
+#define E_IS_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER))
+#define E_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER, EServerSideSourceCredentialsProviderClass))
+
+G_BEGIN_DECLS
+
+typedef struct _EServerSideSourceCredentialsProvider EServerSideSourceCredentialsProvider;
+typedef struct _EServerSideSourceCredentialsProviderClass EServerSideSourceCredentialsProviderClass;
+typedef struct _EServerSideSourceCredentialsProviderPrivate EServerSideSourceCredentialsProviderPrivate;
+
+/**
+ * EServerSideSourceCredentialsProvider:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.14
+ **/
+struct _EServerSideSourceCredentialsProvider {
+       ESourceCredentialsProvider parent;
+       EServerSideSourceCredentialsProviderPrivate *priv;
+};
+
+struct _EServerSideSourceCredentialsProviderClass {
+       ESourceCredentialsProviderClass parent_class;
+};
+
+GType          e_server_side_source_credentials_provider_get_type      (void) G_GNUC_CONST;
+ESourceCredentialsProvider *
+               e_server_side_source_credentials_provider_new           (ESourceRegistryServer *registry);
+G_END_DECLS
+
+#endif /* E_SERVER_SIDE_SOURCE_CREDENTIALS_PROVIDER_H */
diff --git a/libebackend/e-server-side-source.c b/libebackend/e-server-side-source.c
index 91f646c..8e3213e 100644
--- a/libebackend/e-server-side-source.c
+++ b/libebackend/e-server-side-source.c
@@ -27,6 +27,7 @@
 #include "e-server-side-source.h"
 
 #include <config.h>
+#include <stdio.h>
 #include <glib/gi18n-lib.h>
 
 /* Private D-Bus classes. */
@@ -52,9 +53,18 @@ struct _EServerSideSourcePrivate {
        /* For comparison. */
        gchar *file_contents;
 
-       gboolean allow_auth_prompt;
-       GType auth_session_type;
        gchar *write_directory;
+
+       GMutex last_values_lock;
+       gchar *last_reason;
+       gchar *last_certificate_pem;
+       gchar *last_certificate_errors;
+       gchar *last_dbus_error_name;
+       gchar *last_dbus_error_message;
+       ENamedParameters *last_credentials;
+
+       GMutex pending_credentials_lookup_lock;
+       GCancellable *pending_credentials_lookup;
 };
 
 struct _AsyncContext {
@@ -66,8 +76,6 @@ struct _AsyncContext {
 
 enum {
        PROP_0,
-       PROP_ALLOW_AUTH_PROMPT,
-       PROP_AUTH_SESSION_TYPE,
        PROP_EXPORTED,
        PROP_FILE,
        PROP_OAUTH2_SUPPORT,
@@ -192,14 +200,304 @@ server_side_source_traverse_cb (GNode *node,
        return FALSE;
 }
 
+static ESourceCredentialsReason
+server_side_source_credentials_reason_from_text (const gchar *arg_reason)
+{
+       ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
+
+       if (arg_reason && *arg_reason) {
+               GEnumClass *enum_class;
+               GEnumValue *enum_value;
+
+               enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
+               enum_value = g_enum_get_value_by_nick (enum_class, arg_reason);
+
+               if (enum_value) {
+                       reason = enum_value->value;
+               } else {
+                       g_warning ("%s: Unknown reason enum: '%s'", G_STRFUNC, arg_reason);
+               }
+
+               g_type_class_unref (enum_class);
+       }
+
+       return reason;
+}
+
+typedef struct _ReinvokeCredentialsRequiredData {
+       EServerSideSource *source;
+       gchar *arg_reason;
+       gchar *arg_certificate_pem;
+       gchar *arg_certificate_errors;
+       gchar *arg_dbus_error_name;
+       gchar *arg_dbus_error_message;
+} ReinvokeCredentialsRequiredData;
+
+static void
+reinvoke_credentials_required_data_free (gpointer ptr)
+{
+       ReinvokeCredentialsRequiredData *data = ptr;
+
+       if (data) {
+               g_clear_object (&data->source);
+               g_free (data->arg_reason);
+               g_free (data->arg_certificate_pem);
+               g_free (data->arg_certificate_errors);
+               g_free (data->arg_dbus_error_name);
+               g_free (data->arg_dbus_error_message);
+               g_free (data);
+       }
+}
+
+static void server_side_source_credentials_lookup_cb (GObject *source_object, GAsyncResult *result, gpointer 
user_data);
+
 static gboolean
-server_side_source_allow_auth_prompt_cb (EDBusSource *dbus_interface,
-                                         GDBusMethodInvocation *invocation,
-                                         EServerSideSource *source)
+server_side_source_invoke_credentials_required_cb (EDBusSource *dbus_interface,
+                                                  GDBusMethodInvocation *invocation,
+                                                  const gchar *arg_reason,
+                                                  const gchar *arg_certificate_pem,
+                                                  const gchar *arg_certificate_errors,
+                                                  const gchar *arg_dbus_error_name,
+                                                  const gchar *arg_dbus_error_message,
+                                                  EServerSideSource *source)
 {
-       e_server_side_source_set_allow_auth_prompt (source, TRUE);
+       gboolean skip_emit = FALSE;
+
+       if (invocation)
+               e_dbus_source_complete_invoke_credentials_required (dbus_interface, invocation);
 
-       e_dbus_source_complete_allow_auth_prompt (dbus_interface, invocation);
+       g_mutex_lock (&source->priv->pending_credentials_lookup_lock);
+       if (source->priv->pending_credentials_lookup) {
+               g_cancellable_cancel (source->priv->pending_credentials_lookup);
+               g_clear_object (&source->priv->pending_credentials_lookup);
+       }
+       g_mutex_unlock (&source->priv->pending_credentials_lookup_lock);
+
+       g_mutex_lock (&source->priv->last_values_lock);
+
+       g_free (source->priv->last_reason);
+       g_free (source->priv->last_certificate_pem);
+       g_free (source->priv->last_certificate_errors);
+       g_free (source->priv->last_dbus_error_name);
+       g_free (source->priv->last_dbus_error_message);
+       source->priv->last_reason = g_strdup (arg_reason);
+       source->priv->last_certificate_pem = g_strdup (arg_certificate_pem);
+       source->priv->last_certificate_errors = g_strdup (arg_certificate_errors);
+       source->priv->last_dbus_error_name = g_strdup (arg_dbus_error_name);
+       source->priv->last_dbus_error_message = g_strdup (arg_dbus_error_message);
+
+       g_mutex_unlock (&source->priv->last_values_lock);
+
+       /* Do not bother clients, when the password is stored. */
+       if (server_side_source_credentials_reason_from_text (arg_reason) == 
E_SOURCE_CREDENTIALS_REASON_REQUIRED) {
+               ESourceRegistryServer *server;
+               ESourceCredentialsProvider *credentials_provider;
+
+               server = e_server_side_source_get_server (source);
+               credentials_provider = server ? e_source_registry_server_ref_credentials_provider (server) : 
NULL;
+
+               if (credentials_provider) {
+                       ReinvokeCredentialsRequiredData *data;
+                       GCancellable *cancellable;
+
+                       g_mutex_lock (&source->priv->pending_credentials_lookup_lock);
+                       if (source->priv->pending_credentials_lookup) {
+                               g_cancellable_cancel (source->priv->pending_credentials_lookup);
+                               g_clear_object (&source->priv->pending_credentials_lookup);
+                       }
+                       cancellable = g_cancellable_new ();
+                       source->priv->pending_credentials_lookup = g_object_ref (cancellable);
+                       g_mutex_unlock (&source->priv->pending_credentials_lookup_lock);
+
+                       data = g_new0 (ReinvokeCredentialsRequiredData, 1);
+                       data->source = g_object_ref (source);
+                       data->arg_reason = g_strdup (arg_reason);
+                       data->arg_certificate_pem = g_strdup (arg_certificate_pem);
+                       data->arg_certificate_errors = g_strdup (arg_certificate_errors);
+                       data->arg_dbus_error_name = g_strdup (arg_dbus_error_name);
+                       data->arg_dbus_error_message = g_strdup (arg_dbus_error_message);
+
+                       skip_emit = TRUE;
+
+                       e_source_credentials_provider_lookup (credentials_provider, E_SOURCE (source),
+                               cancellable, server_side_source_credentials_lookup_cb, data);
+
+                       g_object_unref (cancellable);
+               }
+
+               g_clear_object (&credentials_provider);
+       }
+
+       if (!skip_emit) {
+               e_dbus_source_emit_credentials_required (dbus_interface, arg_reason, arg_certificate_pem, 
arg_certificate_errors, arg_dbus_error_name, arg_dbus_error_message);
+       }
+
+       return TRUE;
+}
+
+static gboolean
+server_side_source_invoke_authenticate_cb (EDBusSource *dbus_interface,
+                                          GDBusMethodInvocation *invocation,
+                                          const gchar * const *arg_credentials,
+                                          EServerSideSource *source)
+{
+       gchar **last_credentials_strv = NULL;
+
+       g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), TRUE);
+
+       g_mutex_lock (&source->priv->pending_credentials_lookup_lock);
+       if (source->priv->pending_credentials_lookup) {
+               g_cancellable_cancel (source->priv->pending_credentials_lookup);
+               g_clear_object (&source->priv->pending_credentials_lookup);
+       }
+       g_mutex_unlock (&source->priv->pending_credentials_lookup_lock);
+
+       g_mutex_lock (&source->priv->last_values_lock);
+
+       /* Empty credentials are used to use the last credentials instead */
+       if (source->priv->last_credentials && arg_credentials && !arg_credentials[0]) {
+               last_credentials_strv = e_named_parameters_to_strv (source->priv->last_credentials);
+               arg_credentials = (const gchar * const *) last_credentials_strv;
+       } else if (arg_credentials && arg_credentials[0]) {
+               e_named_parameters_free (source->priv->last_credentials);
+               source->priv->last_credentials = e_named_parameters_new_strv (arg_credentials);
+       }
+
+       g_free (source->priv->last_reason);
+       g_free (source->priv->last_certificate_pem);
+       g_free (source->priv->last_certificate_errors);
+       g_free (source->priv->last_dbus_error_name);
+       g_free (source->priv->last_dbus_error_message);
+       source->priv->last_reason = NULL;
+       source->priv->last_certificate_pem = NULL;
+       source->priv->last_certificate_errors = NULL;
+       source->priv->last_dbus_error_name = NULL;
+       source->priv->last_dbus_error_message = NULL;
+
+       g_mutex_unlock (&source->priv->last_values_lock);
+
+       if (invocation)
+               e_dbus_source_complete_invoke_authenticate (dbus_interface, invocation);
+
+       e_dbus_source_emit_authenticate (dbus_interface, arg_credentials);
+
+       g_strfreev (last_credentials_strv);
+
+       return TRUE;
+}
+
+static void
+server_side_source_credentials_lookup_cb (GObject *source_object,
+                                         GAsyncResult *result,
+                                         gpointer user_data)
+{
+       GDBusObject *dbus_object;
+       EDBusSource *dbus_source;
+       ReinvokeCredentialsRequiredData *data = user_data;
+       ENamedParameters *credentials = NULL;
+       gboolean success;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (source_object));
+       g_return_if_fail (data != NULL);
+
+       success = e_source_credentials_provider_lookup_finish (E_SOURCE_CREDENTIALS_PROVIDER (source_object), 
result, &credentials, &error);
+
+       dbus_object = e_source_ref_dbus_object (E_SOURCE (data->source));
+       if (!dbus_object) {
+               e_named_parameters_free (credentials);
+               g_warn_if_fail (dbus_object != NULL);
+               reinvoke_credentials_required_data_free (data);
+               return;
+       }
+
+       dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
+       if (!dbus_source) {
+               e_named_parameters_free (credentials);
+               g_warn_if_fail (dbus_source != NULL);
+               g_object_unref (dbus_object);
+               reinvoke_credentials_required_data_free (data);
+               return;
+       }
+
+       if (success && credentials) {
+               gchar **arg_credentials;
+
+               arg_credentials = e_named_parameters_to_strv (credentials);
+
+               server_side_source_invoke_authenticate_cb (dbus_source, NULL,
+                       (const gchar * const *) arg_credentials, data->source);
+
+               g_strfreev (arg_credentials);
+       } else if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               if (error) {
+                       printf ("%s: Failed to lookup password: %s\n", G_STRFUNC, error ? error->message : 
"Unknown error");
+                       fflush (stdout);
+               }
+
+               if (server_side_source_credentials_reason_from_text (data->arg_reason) == 
E_SOURCE_CREDENTIALS_REASON_REQUIRED &&
+                   error && !e_source_credentials_provider_can_prompt (E_SOURCE_CREDENTIALS_PROVIDER 
(source_object), E_SOURCE (data->source))) {
+                       GEnumClass *enum_class;
+                       GEnumValue *enum_value;
+                       gchar *dbus_error_name;
+
+                       enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
+                       enum_value = g_enum_get_value (enum_class, E_SOURCE_CREDENTIALS_REASON_ERROR);
+
+                       g_return_if_fail (enum_value != NULL);
+
+                       dbus_error_name = g_dbus_error_encode_gerror (error);
+
+                       /* Use error reason when the source cannot be prompted for credentials */
+                       e_dbus_source_emit_credentials_required (dbus_source, enum_value->value_nick,
+                               data->arg_certificate_pem, data->arg_certificate_errors, dbus_error_name, 
error->message);
+
+                       g_type_class_unref (enum_class);
+                       g_free (dbus_error_name);
+               } else {
+                       /* Reinvoke for clients only, if not cancelled */
+                       const gchar *arg_dbus_error_name, *arg_dbus_error_message;
+                       gchar *dbus_error_name = NULL;
+
+                       arg_dbus_error_name = data->arg_dbus_error_name;
+                       arg_dbus_error_message = data->arg_dbus_error_message;
+
+                       if (!arg_dbus_error_name || !*arg_dbus_error_name) {
+                               dbus_error_name = g_dbus_error_encode_gerror (error);
+                               arg_dbus_error_name = dbus_error_name;
+                               arg_dbus_error_message = error->message;
+                       }
+
+                       e_dbus_source_emit_credentials_required (dbus_source, data->arg_reason,
+                               data->arg_certificate_pem, data->arg_certificate_errors,
+                               arg_dbus_error_name, arg_dbus_error_message);
+
+                       g_free (dbus_error_name);
+               }
+       }
+
+       e_named_parameters_free (credentials);
+       reinvoke_credentials_required_data_free (data);
+       g_object_unref (dbus_source);
+       g_object_unref (dbus_object);
+       g_clear_error (&error);
+}
+
+static gboolean
+server_side_source_get_last_credentials_required_arguments_cb (EDBusSource *dbus_interface,
+                                                              GDBusMethodInvocation *invocation,
+                                                              EServerSideSource *source)
+{
+       g_mutex_lock (&source->priv->last_values_lock);
+
+       e_dbus_source_complete_get_last_credentials_required_arguments (dbus_interface, invocation,
+               source->priv->last_reason ? source->priv->last_reason : "",
+               source->priv->last_certificate_pem ? source->priv->last_certificate_pem : "",
+               source->priv->last_certificate_errors ? source->priv->last_certificate_errors : "",
+               source->priv->last_dbus_error_name ? source->priv->last_dbus_error_name : "",
+               source->priv->last_dbus_error_message ? source->priv->last_dbus_error_message : "");
+
+       g_mutex_unlock (&source->priv->last_values_lock);
 
        return TRUE;
 }
@@ -520,18 +818,6 @@ server_side_source_set_property (GObject *object,
                                  GParamSpec *pspec)
 {
        switch (property_id) {
-               case PROP_ALLOW_AUTH_PROMPT:
-                       e_server_side_source_set_allow_auth_prompt (
-                               E_SERVER_SIDE_SOURCE (object),
-                               g_value_get_boolean (value));
-                       return;
-
-               case PROP_AUTH_SESSION_TYPE:
-                       e_server_side_source_set_auth_session_type (
-                               E_SERVER_SIDE_SOURCE (object),
-                               g_value_get_gtype (value));
-                       return;
-
                case PROP_FILE:
                        server_side_source_set_file (
                                E_SERVER_SIDE_SOURCE (object),
@@ -591,20 +877,6 @@ server_side_source_get_property (GObject *object,
                                  GParamSpec *pspec)
 {
        switch (property_id) {
-               case PROP_ALLOW_AUTH_PROMPT:
-                       g_value_set_boolean (
-                               value,
-                               e_server_side_source_get_allow_auth_prompt (
-                               E_SERVER_SIDE_SOURCE (object)));
-                       return;
-
-               case PROP_AUTH_SESSION_TYPE:
-                       g_value_set_gtype (
-                               value,
-                               e_server_side_source_get_auth_session_type (
-                               E_SERVER_SIDE_SOURCE (object)));
-                       return;
-
                case PROP_EXPORTED:
                        g_value_set_boolean (
                                value,
@@ -679,6 +951,31 @@ server_side_source_dispose (GObject *object)
 
        priv = E_SERVER_SIDE_SOURCE_GET_PRIVATE (object);
 
+       g_mutex_lock (&priv->last_values_lock);
+
+       g_free (priv->last_reason);
+       g_free (priv->last_certificate_pem);
+       g_free (priv->last_certificate_errors);
+       g_free (priv->last_dbus_error_name);
+       g_free (priv->last_dbus_error_message);
+       priv->last_reason = NULL;
+       priv->last_certificate_pem = NULL;
+       priv->last_certificate_errors = NULL;
+       priv->last_dbus_error_name = NULL;
+       priv->last_dbus_error_message = NULL;
+
+       e_named_parameters_free (priv->last_credentials);
+       priv->last_credentials = NULL;
+
+       g_mutex_unlock (&priv->last_values_lock);
+
+       g_mutex_lock (&priv->pending_credentials_lookup_lock);
+       if (priv->pending_credentials_lookup) {
+               g_cancellable_cancel (priv->pending_credentials_lookup);
+               g_clear_object (&priv->pending_credentials_lookup);
+       }
+       g_mutex_unlock (&priv->pending_credentials_lookup_lock);
+
        if (priv->server != NULL) {
                g_object_remove_weak_pointer (
                        G_OBJECT (priv->server), &priv->server);
@@ -709,6 +1006,8 @@ server_side_source_finalize (GObject *object)
        g_free (priv->write_directory);
 
        g_weak_ref_clear (&priv->oauth2_support);
+       g_mutex_clear (&priv->last_values_lock);
+       g_mutex_clear (&priv->pending_credentials_lookup_lock);
 
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_server_side_source_parent_class)->finalize (object);
@@ -1125,6 +1424,41 @@ server_side_source_get_oauth2_access_token_sync (ESource *source,
 }
 
 static gboolean
+server_side_source_invoke_credentials_required_impl (ESource *source,
+                                                    gpointer dbus_source, /* EDBusSource * */
+                                                    const gchar *arg_reason,
+                                                    const gchar *arg_certificate_pem,
+                                                    const gchar *arg_certificate_errors,
+                                                    const gchar *arg_dbus_error_name,
+                                                    const gchar *arg_dbus_error_message,
+                                                    GCancellable *cancellable,
+                                                    GError **error)
+{
+       g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
+
+       return server_side_source_invoke_credentials_required_cb (dbus_source, NULL,
+               arg_reason ? arg_reason : "",
+               arg_certificate_pem ? arg_certificate_pem : "",
+               arg_certificate_errors ? arg_certificate_errors : "",
+               arg_dbus_error_name ? arg_dbus_error_name : "",
+               arg_dbus_error_message ? arg_dbus_error_message : "",
+               E_SERVER_SIDE_SOURCE (source));
+}
+
+static gboolean
+server_side_source_invoke_authenticate_impl (ESource *source,
+                                            gpointer dbus_source, /* EDBusSource * */
+                                            const gchar * const *arg_credentials,
+                                            GCancellable *cancellable,
+                                            GError **error)
+{
+       g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
+
+       return server_side_source_invoke_authenticate_cb (dbus_source, NULL,
+               arg_credentials, E_SERVER_SIDE_SOURCE (source));
+}
+
+static gboolean
 server_side_source_initable_init (GInitable *initable,
                                   GCancellable *cancellable,
                                   GError **error)
@@ -1150,8 +1484,14 @@ server_side_source_initable_init (GInitable *initable,
        g_object_unref (dbus_object);
 
        g_signal_connect (
-               dbus_source, "handle-allow-auth-prompt",
-               G_CALLBACK (server_side_source_allow_auth_prompt_cb), source);
+               dbus_source, "handle-invoke-credentials-required",
+               G_CALLBACK (server_side_source_invoke_credentials_required_cb), source);
+       g_signal_connect (
+               dbus_source, "handle-invoke-authenticate",
+               G_CALLBACK (server_side_source_invoke_authenticate_cb), source);
+       g_signal_connect (
+               dbus_source, "handle-get-last-credentials-required-arguments",
+               G_CALLBACK (server_side_source_get_last_credentials_required_arguments_cb), source);
 
        g_object_unref (dbus_source);
 
@@ -1184,37 +1524,11 @@ e_server_side_source_class_init (EServerSideSourceClass *class)
        source_class->write_sync = server_side_source_write_sync;
        source_class->write = server_side_source_write;
        source_class->write_finish = server_side_source_write_finish;
-       source_class->remote_create_sync =
-               server_side_source_remote_create_sync;
-       source_class->remote_delete_sync =
-               server_side_source_remote_delete_sync;
-       source_class->get_oauth2_access_token_sync =
-               server_side_source_get_oauth2_access_token_sync;
-
-       g_object_class_install_property (
-               object_class,
-               PROP_ALLOW_AUTH_PROMPT,
-               g_param_spec_boolean (
-                       "allow-auth-prompt",
-                       "Allow Auth Prompt",
-                       "Whether authentication sessions may "
-                       "interrupt the user for a password",
-                       TRUE,
-                       G_PARAM_READWRITE |
-                       G_PARAM_CONSTRUCT |
-                       G_PARAM_STATIC_STRINGS));
-
-       g_object_class_install_property (
-               object_class,
-               PROP_AUTH_SESSION_TYPE,
-               g_param_spec_gtype (
-                       "auth-session-type",
-                       "Auth Session Type",
-                       "The type of authentication session "
-                       "to instantiate for this source",
-                       E_TYPE_AUTHENTICATION_SESSION,
-                       G_PARAM_READWRITE |
-                       G_PARAM_STATIC_STRINGS));
+       source_class->remote_create_sync = server_side_source_remote_create_sync;
+       source_class->remote_delete_sync = server_side_source_remote_delete_sync;
+       source_class->get_oauth2_access_token_sync = server_side_source_get_oauth2_access_token_sync;
+       source_class->invoke_credentials_required_impl = server_side_source_invoke_credentials_required_impl;
+       source_class->invoke_authenticate_impl = server_side_source_invoke_authenticate_impl;
 
        g_object_class_install_property (
                object_class,
@@ -1350,9 +1664,9 @@ e_server_side_source_init (EServerSideSource *source)
        user_dir = e_server_side_source_get_user_dir ();
        source->priv->write_directory = g_strdup (user_dir);
 
-       source->priv->auth_session_type = E_TYPE_AUTHENTICATION_SESSION;
-
        g_weak_ref_init (&source->priv->oauth2_support, NULL);
+       g_mutex_init (&source->priv->last_values_lock);
+       g_mutex_init (&source->priv->pending_credentials_lookup_lock);
 }
 
 /**
@@ -1710,122 +2024,6 @@ e_server_side_source_get_server (EServerSideSource *source)
 }
 
 /**
- * e_server_side_source_get_allow_auth_prompt:
- * @source: an #EServerSideSource
- *
- * Returns whether an authentication prompt is allowed to be shown
- * for @source.  #EAuthenticationSession will honor this setting by
- * dismissing the session if it can't find a valid stored password.
- *
- * See e_server_side_source_set_allow_auth_prompt() for further
- * discussion.
- *
- * Returns: whether auth prompts are allowed for @source
- *
- * Since: 3.6
- **/
-gboolean
-e_server_side_source_get_allow_auth_prompt (EServerSideSource *source)
-{
-       g_return_val_if_fail (E_IS_SERVER_SIDE_SOURCE (source), FALSE);
-
-       return source->priv->allow_auth_prompt;
-}
-
-/**
- * e_server_side_source_set_allow_auth_prompt:
- * @source: an #EServerSideSource
- * @allow_auth_prompt: whether auth prompts are allowed for @source
- *
- * Sets whether an authentication prompt is allowed to be shown for @source.
- * #EAuthenticationSession will honor this setting by dismissing the session
- * if it can't find a valid stored password.
- *
- * If the user declines to provide a password for @source when prompted
- * by an #EAuthenticationSession, the #ESourceRegistryServer will set this
- * property to %FALSE to suppress any further prompting, which would likely
- * annoy the user.  However when an #ESourceRegistry instance is created by
- * a client application, the first thing it does is reset this property to
- * %TRUE for all registered data sources.  So suppressing authentication
- * prompts is only ever temporary.
- *
- * Since: 3.6
- **/
-void
-e_server_side_source_set_allow_auth_prompt (EServerSideSource *source,
-                                            gboolean allow_auth_prompt)
-{
-       g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
-
-       if (source->priv->allow_auth_prompt == allow_auth_prompt)
-               return;
-
-       source->priv->allow_auth_prompt = allow_auth_prompt;
-
-       g_object_notify (G_OBJECT (source), "allow-auth-prompt");
-}
-
-/**
- * e_server_side_source_get_auth_session_type:
- * @source: an #EServerSideSource
- *
- * Returns the type of authentication session to use for @source,
- * which will get passed to e_source_registry_server_authenticate().
- *
- * This defaults to the #GType for #EAuthenticationSession.
- *
- * Returns: the type of authentication session to use for @source
- *
- * Since: 3.8
- **/
-GType
-e_server_side_source_get_auth_session_type (EServerSideSource *source)
-{
-       g_return_val_if_fail (
-               E_IS_SERVER_SIDE_SOURCE (source),
-               E_TYPE_AUTHENTICATION_SESSION);
-
-       return source->priv->auth_session_type;
-}
-
-/**
- * e_server_side_source_set_auth_session_type:
- * @source: an #EServerSideSource
- * @auth_session_type: the type of authentication session to use for @source
- *
- * Sets the type of authentication session to use for @source, which will
- * get passed to e_source_registry_server_authenticate().
- *
- * @auth_session_type must be derived from #EAuthenticationSession, or else
- * the function will reject the #GType with a runtime warning.
- *
- * This defaults to the #GType for #EAuthenticationSession.
- *
- * Since: 3.8
- **/
-void
-e_server_side_source_set_auth_session_type (EServerSideSource *source,
-                                            GType auth_session_type)
-{
-       g_return_if_fail (E_IS_SERVER_SIDE_SOURCE (source));
-
-       if (!g_type_is_a (auth_session_type, E_TYPE_AUTHENTICATION_SESSION)) {
-               g_warning (
-                       "Invalid auth session type '%s' for source '%s'",
-                       g_type_name (auth_session_type),
-                       e_source_get_display_name (E_SOURCE (source)));
-               return;
-       }
-
-       if (auth_session_type == source->priv->auth_session_type)
-               return;
-
-       source->priv->auth_session_type = auth_session_type;
-
-       g_object_notify (G_OBJECT (source), "auth-session-type");
-}
-
-/**
  * e_server_side_source_get_exported:
  * @source: an #EServerSideSource
  *
@@ -2205,4 +2403,3 @@ e_server_side_source_set_oauth2_support (EServerSideSource *source,
 
        g_object_notify (G_OBJECT (source), "oauth2-support");
 }
-
diff --git a/libebackend/e-server-side-source.h b/libebackend/e-server-side-source.h
index cd7ac31..c5fca9d 100644
--- a/libebackend/e-server-side-source.h
+++ b/libebackend/e-server-side-source.h
@@ -22,8 +22,6 @@
 #ifndef E_SERVER_SIDE_SOURCE_H
 #define E_SERVER_SIDE_SOURCE_H
 
-#include <libedataserver/libedataserver.h>
-
 #include <libebackend/e-oauth2-support.h>
 #include <libebackend/e-source-registry-server.h>
 
@@ -91,16 +89,6 @@ GFile *              e_server_side_source_get_file   (EServerSideSource *source);
 GNode *                e_server_side_source_get_node   (EServerSideSource *source);
 ESourceRegistryServer *
                e_server_side_source_get_server (EServerSideSource *source);
-gboolean       e_server_side_source_get_allow_auth_prompt
-                                               (EServerSideSource *source);
-void           e_server_side_source_set_allow_auth_prompt
-                                               (EServerSideSource *source,
-                                                gboolean allow_auth_prompt);
-GType          e_server_side_source_get_auth_session_type
-                                               (EServerSideSource *source);
-void           e_server_side_source_set_auth_session_type
-                                               (EServerSideSource *source,
-                                                GType auth_session_type);
 gboolean       e_server_side_source_get_exported
                                                (EServerSideSource *source);
 const gchar *  e_server_side_source_get_write_directory
diff --git a/libebackend/e-soup-ssl-trust.c b/libebackend/e-soup-ssl-trust.c
index d0f10a6..2fa3258 100644
--- a/libebackend/e-soup-ssl-trust.c
+++ b/libebackend/e-soup-ssl-trust.c
@@ -34,41 +34,10 @@
 typedef struct _ESoupSslTrustData {
        SoupMessage *soup_message; /* weak */
        ESource *source;
-       ESourceRegistry *registry;
-       GCancellable *cancellable;
 
        GClosure *accept_certificate_closure;
 } ESoupSslTrustData;
 
-static ETrustPromptResponse
-trust_prompt_sync (const ENamedParameters *parameters,
-                   GCancellable *cancellable,
-                   GError **error)
-{
-       EUserPrompter *prompter;
-       gint response;
-
-       g_return_val_if_fail (parameters != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
-
-       prompter = e_user_prompter_new ();
-       g_return_val_if_fail (prompter != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
-
-       response = e_user_prompter_extension_prompt_sync (prompter, "ETrustPrompt::trust-prompt", parameters, 
NULL, cancellable, error);
-
-       g_object_unref (prompter);
-
-       if (response == 0)
-               return E_TRUST_PROMPT_RESPONSE_REJECT;
-       if (response == 1)
-               return E_TRUST_PROMPT_RESPONSE_ACCEPT;
-       if (response == 2)
-               return E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY;
-       if (response == -1)
-               return E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY;
-
-       return E_TRUST_PROMPT_RESPONSE_UNKNOWN;
-}
-
 static gboolean
 e_soup_ssl_trust_accept_certificate_cb (GTlsConnection *conn,
                                        GTlsCertificate *peer_cert,
@@ -77,22 +46,38 @@ e_soup_ssl_trust_accept_certificate_cb (GTlsConnection *conn,
 {
        ESoupSslTrustData *handler = user_data;
        ETrustPromptResponse response;
-       ENamedParameters *parameters;
-
-       parameters = e_named_parameters_new ();
+       SoupURI *soup_uri;
+       const gchar *host;
+       gchar *auth_host = NULL;
+
+       soup_uri = soup_message_get_uri (handler->soup_message);
+       if (!soup_uri || !soup_uri_get_host (soup_uri))
+               return FALSE;
+
+       host = soup_uri_get_host (soup_uri);
+
+       if (e_source_has_extension (handler->source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
+               ESourceAuthentication *extension_authentication;
+
+               extension_authentication = e_source_get_extension (handler->source, 
E_SOURCE_EXTENSION_AUTHENTICATION);
+               auth_host = e_source_authentication_dup_host (extension_authentication);
+
+               if (auth_host && *auth_host) {
+                       /* Use the 'host' from the Authentication extension, because
+                          it's the one used when storing the trust prompt result.
+                          The SoupMessage can be redirected, thus it would not ever match. */
+                       host = auth_host;
+               } else {
+                       g_free (auth_host);
+                       auth_host = NULL;
+               }
+       }
 
-       response = e_source_webdav_prepare_ssl_trust_prompt (
+       response = e_source_webdav_verify_ssl_trust (
                e_source_get_extension (handler->source, E_SOURCE_EXTENSION_WEBDAV_BACKEND),
-               handler->soup_message, peer_cert, errors, handler->registry, parameters);
-       if (response == E_TRUST_PROMPT_RESPONSE_UNKNOWN) {
-               response = trust_prompt_sync (parameters, handler->cancellable, NULL);
-               if (response != E_TRUST_PROMPT_RESPONSE_UNKNOWN)
-                       e_source_webdav_store_ssl_trust_prompt (
-                               e_source_get_extension (handler->source, E_SOURCE_EXTENSION_WEBDAV_BACKEND),
-                               handler->soup_message, peer_cert, response);
-       }
+               host, peer_cert, errors);
 
-       e_named_parameters_free (parameters);
+       g_free (auth_host);
 
        return (response == E_TRUST_PROMPT_RESPONSE_ACCEPT ||
                response == E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY);
@@ -126,8 +111,6 @@ e_soup_ssl_trust_message_finalized_cb (gpointer data,
        handler = data;
 
        g_clear_object (&handler->source);
-       g_clear_object (&handler->registry);
-       g_clear_object (&handler->cancellable);
 
        /* Synchronously disconnects the accept certificate handler from all
         * GTlsConnections. */
@@ -141,31 +124,26 @@ e_soup_ssl_trust_message_finalized_cb (gpointer data,
  * e_soup_ssl_trust_connect:
  * @soup_message: a #SoupMessage about to be sent to the source
  * @source: an #ESource that uses WebDAV
- * @registry: (allow-none): an #ESourceRegistry, to use for parent lookups
- * @cancellable: (allow-none): #GCancellable to cancel the trust prompt
  *
- * Sets up automatic SSL certificate trust handling for @message using the trust
- * data stored in @source's WebDAV extension. If @message is about to be sent on
+ * Sets up automatic SSL certificate trust handling for @soup_message using the trust
+ * data stored in @source's WebDAV extension. If @soup_message is about to be sent on
  * an SSL connection with an invalid certificate, the code checks if the WebDAV
- * extension already has a trust response for that certificate with
- * e_source_webdav_prepare_ssl_trust_prompt and if not, prompts the user with
- * the "ETrustPrompt::trust-prompt" extension dialog and
- * saves the result with e_source_webdav_store_ssl_trust_prompt.
+ * extension already has a trust response for that certificate and verifies it
+ * with e_source_webdav_verify_ssl_trust(). If the verification fails, then
+ * the @soup_message send also fails.
  *
- * This works by connecting to the "network-event" signal on @message and
+ * This works by connecting to the "network-event" signal on @soup_message and
  * connecting to the "accept-certificate" signal on each #GTlsConnection for
- * which @message reports a #G_SOCKET_CLIENT_TLS_HANDSHAKING event. These
- * handlers are torn down automatically when @message is disposed. This process
- * is not thread-safe; it is sufficient for safety if all use of @message's
- * session and the disposal of @message occur in the same thread.
+ * which @soup_message reports a #G_SOCKET_CLIENT_TLS_HANDSHAKING event. These
+ * handlers are torn down automatically when @soup_message is disposed. This process
+ * is not thread-safe; it is sufficient for safety if all use of @soup_message's
+ * session and the disposal of @soup_message occur in the same thread.
  *
  * Since: 3.14
  **/
 void
 e_soup_ssl_trust_connect (SoupMessage *soup_message,
-                          ESource *source,
-                          ESourceRegistry *registry,
-                          GCancellable *cancellable)
+                          ESource *source)
 {
        ESoupSslTrustData *handler;
 
@@ -176,8 +154,6 @@ e_soup_ssl_trust_connect (SoupMessage *soup_message,
        handler->soup_message = soup_message;
        g_object_weak_ref (G_OBJECT (soup_message), e_soup_ssl_trust_message_finalized_cb, handler);
        handler->source = g_object_ref (source);
-       handler->registry = registry ? g_object_ref (registry) : NULL;
-       handler->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
        handler->accept_certificate_closure = g_cclosure_new (G_CALLBACK 
(e_soup_ssl_trust_accept_certificate_cb), handler, NULL);
 
        g_closure_ref (handler->accept_certificate_closure);
diff --git a/libebackend/e-soup-ssl-trust.h b/libebackend/e-soup-ssl-trust.h
index 846585d..7dbdf09 100644
--- a/libebackend/e-soup-ssl-trust.h
+++ b/libebackend/e-soup-ssl-trust.h
@@ -29,9 +29,7 @@
 G_BEGIN_DECLS
 
 void           e_soup_ssl_trust_connect        (SoupMessage *soup_message,
-                                                ESource *source,
-                                                ESourceRegistry *registry,
-                                                GCancellable *cancellable);
+                                                ESource *source);
 
 G_END_DECLS
 
diff --git a/libebackend/e-source-registry-server.c b/libebackend/e-source-registry-server.c
index 5ff0efe..741920b 100644
--- a/libebackend/e-source-registry-server.c
+++ b/libebackend/e-source-registry-server.c
@@ -23,9 +23,8 @@
  * The #ESourceRegistryServer is the heart of the registry D-Bus service.
  * Acting as a global singleton store for all #EServerSideSource instances,
  * its responsibilities include loading data source content from key files,
- * exporting data sources to clients over D-Bus, handling authentication
- * and content change requests from clients, and saving content changes
- * back to key files.
+ * exporting data sources to clients over D-Bus, handling content change
+ * requests from clients, and saving content changes back to key files.
  *
  * It also hosts any number of built-in or 3rd party data source collection
  * backends, which coordinate with #ESourceRegistryServer to automatically
@@ -42,9 +41,8 @@
 #include <e-dbus-source.h>
 #include <e-dbus-source-manager.h>
 
-#include <libebackend/e-authentication-mediator.h>
-#include <libebackend/e-authentication-session.h>
-#include <libebackend/e-server-side-source.h>
+#include "e-server-side-source.h"
+#include "e-server-side-source-credentials-provider.h"
 
 #define E_SOURCE_REGISTRY_SERVER_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -54,8 +52,6 @@
  * sources with a [Collection] extension. */
 #define BACKEND_DATA_KEY "__e_collection_backend__"
 
-typedef struct _AuthRequest AuthRequest;
-
 struct _ESourceRegistryServerPrivate {
        GMainContext *main_context;
 
@@ -69,30 +65,7 @@ struct _ESourceRegistryServerPrivate {
        GMutex sources_lock;
        GMutex orphans_lock;
 
-       /* In pseudo-Python notation:
-        *
-        * running_auths = { UID : AuthRequest }
-        * waiting_auths = { UID : [ AuthRequest, ... ] }
-        *
-        * We process all authenticators for a given source UID at once.
-        * The thought being after the first authenticator for a given UID
-        * completes (the first being most likely to trigger a user prompt),
-        * then any other authenticators for that same UID should complete
-        * quickly, hopefully without having to reprompt.  That is unless
-        * the user decides not to cache the secret at all, in which case
-        * he gets what he asked for: lots of annoying prompts.
-        */
-       GMutex auth_lock;
-       GHashTable *running_auths;
-       GHashTable *waiting_auths;
-};
-
-struct _AuthRequest {
-       volatile gint ref_count;
-       EAuthenticationSession *session;
-       GSimpleAsyncResult *simple;
-       ESource *source;  /* may be NULL */
-       GCancellable *cancellable;
+       ESourceCredentialsProvider *credentials_provider;
 };
 
 enum {
@@ -104,11 +77,6 @@ enum {
        LAST_SIGNAL
 };
 
-/* Forward Declarations */
-static void    source_registry_server_maybe_start_auth_session
-                                               (ESourceRegistryServer *server,
-                                                const gchar *uid);
-
 static guint signals[LAST_SIGNAL];
 
 G_DEFINE_TYPE (
@@ -116,65 +84,6 @@ G_DEFINE_TYPE (
        e_source_registry_server,
        E_TYPE_DATA_FACTORY)
 
-static AuthRequest *
-auth_request_new (EAuthenticationSession *session,
-                  GSimpleAsyncResult *simple,
-                  GCancellable *cancellable)
-{
-       ESourceRegistryServer *server;
-       AuthRequest *request;
-       const gchar *uid;
-
-       server = e_authentication_session_get_server (session);
-       uid = e_authentication_session_get_source_uid (session);
-
-       request = g_slice_new0 (AuthRequest);
-       request->ref_count = 1;
-       request->session = g_object_ref (session);
-       request->simple = g_object_ref (simple);
-
-       /* This will return NULL if the authenticating data source
-        * has not yet been submitted to the D-Bus registry server. */
-       request->source = e_source_registry_server_ref_source (server, uid);
-
-       if (G_IS_CANCELLABLE (cancellable))
-               request->cancellable = g_object_ref (cancellable);
-
-       return request;
-}
-
-static AuthRequest *
-auth_request_ref (AuthRequest *request)
-{
-       g_return_val_if_fail (request != NULL, NULL);
-       g_return_val_if_fail (request->ref_count > 0, NULL);
-
-       g_atomic_int_inc (&request->ref_count);
-
-       return request;
-}
-
-static void
-auth_request_unref (AuthRequest *request)
-{
-       g_return_if_fail (request != NULL);
-       g_return_if_fail (request->ref_count > 0);
-
-       if (g_atomic_int_dec_and_test (&request->ref_count)) {
-
-               g_object_unref (request->session);
-               g_object_unref (request->simple);
-
-               if (request->source != NULL)
-                       g_object_unref (request->source);
-
-               if (request->cancellable != NULL)
-                       g_object_unref (request->cancellable);
-
-               g_slice_free (AuthRequest, request);
-       }
-}
-
 /* GDestroyNotify callback for 'sources' values */
 static void
 unref_data_source (ESource *source)
@@ -184,17 +93,6 @@ unref_data_source (ESource *source)
        g_object_unref (source);
 }
 
-/* GDestroyNotify callback for 'waiting_auths' values */
-static void
-free_auth_queue (GQueue *queue)
-{
-       /* XXX g_queue_clear_full() would be nice here. */
-       while (!g_queue_is_empty (queue))
-               g_object_unref (g_queue_pop_head (queue));
-
-       g_queue_free (queue);
-}
-
 static void
 source_registry_server_sources_insert (ESourceRegistryServer *server,
                                        ESource *source)
@@ -367,384 +265,6 @@ source_registry_server_orphans_steal (ESourceRegistryServer *server,
        return array;
 }
 
-static void
-source_request_server_auth_request_cancel_all (ESourceRegistryServer *server)
-{
-       GHashTableIter iter;
-       gpointer value;
-
-       g_mutex_lock (&server->priv->auth_lock);
-
-       g_hash_table_iter_init (&iter, server->priv->waiting_auths);
-
-       while (g_hash_table_iter_next (&iter, NULL, &value)) {
-               GQueue *queue = value;
-               GList *list, *link;
-
-               list = g_queue_peek_head_link (queue);
-
-               for (link = list; link != NULL; link = g_list_next (link)) {
-                       AuthRequest *request = link->data;
-                       g_cancellable_cancel (request->cancellable);
-               }
-       }
-
-       g_hash_table_iter_init (&iter, server->priv->running_auths);
-
-       while (g_hash_table_iter_next (&iter, NULL, &value)) {
-               AuthRequest *request = value;
-               g_cancellable_cancel (request->cancellable);
-       }
-
-       g_mutex_unlock (&server->priv->auth_lock);
-}
-
-static void
-source_registry_server_auth_request_push (ESourceRegistryServer *server,
-                                          const gchar *uid,
-                                          AuthRequest *request)
-{
-       GQueue *queue;
-
-       g_return_if_fail (uid != NULL);
-
-       g_mutex_lock (&server->priv->auth_lock);
-
-       queue = g_hash_table_lookup (server->priv->waiting_auths, uid);
-
-       if (queue == NULL) {
-               queue = g_queue_new ();
-               g_hash_table_insert (
-                       server->priv->waiting_auths,
-                       g_strdup (uid), queue);
-       }
-
-       g_queue_push_tail (queue, auth_request_ref (request));
-
-       g_mutex_unlock (&server->priv->auth_lock);
-}
-
-static AuthRequest *
-source_registry_server_auth_request_next (ESourceRegistryServer *server,
-                                          const gchar *uid)
-{
-       AuthRequest *request = NULL;
-
-       g_return_val_if_fail (uid != NULL, NULL);
-
-       g_mutex_lock (&server->priv->auth_lock);
-
-       /* If we're already busy processing an authentication request
-        * for this UID, the next request will have to wait in line. */
-       if (!g_hash_table_contains (server->priv->running_auths, uid)) {
-               GQueue *queue;
-
-               queue = g_hash_table_lookup (
-                       server->priv->waiting_auths, uid);
-
-               if (queue != NULL)
-                       request = g_queue_pop_head (queue);
-
-               if (request != NULL)
-                       g_hash_table_insert (
-                               server->priv->running_auths,
-                               g_strdup (uid),
-                               auth_request_ref (request));
-       }
-
-       g_mutex_unlock (&server->priv->auth_lock);
-
-       return request;
-}
-
-static void
-source_registry_server_auth_request_done (ESourceRegistryServer *server,
-                                          const gchar *uid)
-{
-       g_return_if_fail (uid != NULL);
-
-       g_mutex_lock (&server->priv->auth_lock);
-
-       g_hash_table_remove (server->priv->running_auths, uid);
-
-       g_mutex_unlock (&server->priv->auth_lock);
-}
-
-static void
-source_registry_server_auth_session_cb (GObject *source_object,
-                                        GAsyncResult *result,
-                                        gpointer user_data)
-{
-       ESourceRegistryServer *server;
-       EAuthenticationSession *session;
-       EAuthenticationSessionResult auth_result;
-       AuthRequest *request;
-       const gchar *uid;
-       GError *error = NULL;
-
-       session = E_AUTHENTICATION_SESSION (source_object);
-       request = (AuthRequest *) user_data;
-
-       auth_result = e_authentication_session_execute_finish (
-               session, result, &error);
-
-       if (error != NULL) {
-               ESourceAuthenticator *authenticator;
-
-               g_warn_if_fail (auth_result == E_AUTHENTICATION_SESSION_ERROR);
-               g_simple_async_result_take_error (request->simple, error);
-
-               /* If the authenticator is an EAuthenticationMediator,
-                * have it emit a "server-error" signal to the client. */
-               authenticator =
-                       e_authentication_session_get_authenticator (session);
-               if (E_IS_AUTHENTICATION_MEDIATOR (authenticator))
-                       e_authentication_mediator_server_error (
-                               E_AUTHENTICATION_MEDIATOR (authenticator),
-                               error);
-       }
-
-       /* Authentication dismissals require additional handling. */
-       if (auth_result == E_AUTHENTICATION_SESSION_DISMISSED) {
-               ESourceAuthenticator *authenticator;
-
-               /* If the authenticator is an EAuthenticationMediator,
-                * have it emit a "dismissed" signal to the client. */
-               authenticator =
-                       e_authentication_session_get_authenticator (session);
-               if (E_IS_AUTHENTICATION_MEDIATOR (authenticator))
-                       e_authentication_mediator_dismiss (
-                               E_AUTHENTICATION_MEDIATOR (authenticator));
-
-               /* Prevent further user interruptions. */
-               if (request->source != NULL)
-                       e_server_side_source_set_allow_auth_prompt (
-                               E_SERVER_SIDE_SOURCE (request->source), FALSE);
-
-               /* e_source_registry_server_authenticate_finish() should
-                * return an error since authentication did not complete. */
-               g_simple_async_result_set_error (
-                       request->simple,
-                       G_IO_ERROR, G_IO_ERROR_CANCELLED,
-                       _("The user declined to authenticate"));
-       }
-
-       g_simple_async_result_complete_in_idle (request->simple);
-
-       server = e_authentication_session_get_server (session);
-       uid = e_authentication_session_get_source_uid (session);
-
-       source_registry_server_auth_request_done (server, uid);
-       source_registry_server_maybe_start_auth_session (server, uid);
-
-       auth_request_unref (request);
-}
-
-static gboolean
-source_registry_server_start_auth_session_idle_cb (gpointer user_data)
-{
-       AuthRequest *request = user_data;
-
-       /* Execute the new active auth session.  This signals it to
-        * respond with a cached secret in the keyring if it can, or
-        * else show an authentication prompt and wait for input. */
-       e_authentication_session_execute (
-               request->session,
-               G_PRIORITY_DEFAULT,
-               request->cancellable,
-               source_registry_server_auth_session_cb,
-               auth_request_ref (request));
-
-       return FALSE;
-}
-
-static void
-source_registry_server_maybe_start_auth_session (ESourceRegistryServer *server,
-                                                 const gchar *uid)
-{
-       AuthRequest *request;
-
-       /* We own the returned reference, unless we get NULL. */
-       request = source_registry_server_auth_request_next (server, uid);
-
-       if (request != NULL) {
-               GSource *idle_source;
-
-               /* Process the next AuthRequest from an idle callback
-                * on our own GMainContext, since the current thread-
-                * default GMainContext may only be temporary. */
-               idle_source = g_idle_source_new ();
-               g_source_set_callback (
-                       idle_source,
-                       source_registry_server_start_auth_session_idle_cb,
-                       auth_request_ref (request),
-                       (GDestroyNotify) auth_request_unref);
-               g_source_attach (idle_source, server->priv->main_context);
-               g_source_unref (idle_source);
-
-               auth_request_unref (request);
-       }
-}
-
-static void
-source_registry_server_authenticate_done_cb (GObject *source_object,
-                                             GAsyncResult *result,
-                                             gpointer user_data)
-{
-       GError *error = NULL;
-
-       e_source_registry_server_authenticate_finish (
-               E_SOURCE_REGISTRY_SERVER (source_object), result, &error);
-
-       /* Ignore cancellations. */
-       if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
-               g_error_free (error);
-
-       } else if (error != NULL) {
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-}
-
-static void
-source_registry_server_wait_for_client_cb (GObject *source_object,
-                                           GAsyncResult *result,
-                                           gpointer user_data)
-{
-       EAuthenticationMediator *mediator;
-       EAuthenticationSession *session;
-       GError *error = NULL;
-
-       mediator = E_AUTHENTICATION_MEDIATOR (source_object);
-       session = E_AUTHENTICATION_SESSION (user_data);
-
-       e_authentication_mediator_wait_for_client_finish (
-               mediator, result, &error);
-
-       if (error == NULL) {
-               ESourceRegistryServer *server;
-
-               server = e_authentication_session_get_server (session);
-
-               /* Client is ready and waiting to test passwords, so
-                * execute the authentication session as soon as all
-                * other authentication sessions for this same data
-                * source are finished.
-                *
-                * XXX Note this asynchronous operation is not cancellable
-                *     but it does time out on its own after a few minutes. */
-               e_source_registry_server_authenticate (
-                       server, session, NULL,
-                       source_registry_server_authenticate_done_cb, NULL);
-
-       } else {
-               /* Most likely the client went dark and the operation
-                * timed out.  Emit a dismissed signal anyway just in
-                * case the client is still alive and listening. */
-               e_authentication_mediator_dismiss (mediator);
-               g_warning ("%s: %s", G_STRFUNC, error->message);
-               g_error_free (error);
-       }
-
-       g_object_unref (session);
-}
-
-static gboolean
-source_registry_server_allow_auth_prompt_all_cb (EDBusSourceManager *dbus_interface,
-                                                 GDBusMethodInvocation *invocation,
-                                                 ESourceRegistryServer *server)
-{
-       GList *list, *link;
-
-       list = e_source_registry_server_list_sources (server, NULL);
-
-       for (link = list; link != NULL; link = g_list_next (link))
-               e_server_side_source_set_allow_auth_prompt (
-                       E_SERVER_SIDE_SOURCE (link->data), TRUE);
-
-       g_list_free_full (list, (GDestroyNotify) g_object_unref);
-
-       e_dbus_source_manager_complete_allow_auth_prompt_all (
-               dbus_interface, invocation);
-
-       return TRUE;
-}
-
-static gboolean
-source_registry_server_authenticate_cb (EDBusSourceManager *dbus_interface,
-                                        GDBusMethodInvocation *invocation,
-                                        const gchar *source_uid,
-                                        const gchar *prompt_title,
-                                        const gchar *prompt_message,
-                                        const gchar *prompt_description,
-                                        ESourceRegistryServer *server)
-{
-       GDBusConnection *connection;
-       EAuthenticationSession *session;
-       ESourceAuthenticator *authenticator;
-       const gchar *sender;
-       gchar *auth_object_path;
-       GError *error = NULL;
-
-       /* Export the D-Bus interface to a unique object path.  This
-        * effectively starts a new authentication session with the
-        * method caller. */
-
-       connection = g_dbus_method_invocation_get_connection (invocation);
-       sender = g_dbus_method_invocation_get_sender (invocation);
-
-       auth_object_path = e_data_factory_construct_path (
-               E_DATA_FACTORY (server));
-
-       authenticator = e_authentication_mediator_new (
-               connection, auth_object_path, sender, &error);
-
-       if (error != NULL) {
-               g_warn_if_fail (authenticator == NULL);
-               g_dbus_method_invocation_take_error (invocation, error);
-               g_free (auth_object_path);
-               return TRUE;
-       }
-
-       g_return_val_if_fail (
-               E_IS_SOURCE_AUTHENTICATOR (authenticator), FALSE);
-
-       /* Create the authentication session. */
-       session = e_source_registry_server_new_auth_session (
-               server, authenticator, source_uid);
-
-       /* Configure the authentication session. */
-       g_object_set (
-               session,
-               "prompt-title", prompt_title,
-               "prompt-message", prompt_message,
-               "prompt-description", prompt_description,
-               NULL);
-
-       /* Before adding the authentication session to the server we
-        * must handshake with the client requesting authentication.
-        * We do this by returning the object path of the exported
-        * Authenticator interface and then waiting for the client to
-        * acknowledge by calling the Ready() method on the interface.
-        * This indicates the client is ready to receive signals.
-        *
-        * XXX Note this asynchronous operation is not cancellable
-        *     but it does time out on its own after a few minutes. */
-       e_authentication_mediator_wait_for_client (
-               E_AUTHENTICATION_MEDIATOR (authenticator),
-               NULL, source_registry_server_wait_for_client_cb,
-               g_object_ref (session));
-
-       e_dbus_source_manager_complete_authenticate (
-               dbus_interface, invocation, auth_object_path);
-
-       g_object_unref (authenticator);
-       g_object_unref (session);
-       g_free (auth_object_path);
-
-       return TRUE;
-}
-
 static gboolean
 source_registry_server_create_source (ESourceRegistryServer *server,
                                       const gchar *uid,
@@ -1036,6 +556,19 @@ source_registry_server_adopt_orphans (ESourceRegistryServer *server,
 }
 
 static void
+source_registry_server_constructed (GObject *object)
+{
+       ESourceRegistryServer *server;
+
+       server = E_SOURCE_REGISTRY_SERVER (object);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_source_registry_server_parent_class)->constructed (object);
+
+       server->priv->credentials_provider = e_server_side_source_credentials_provider_new (server);
+}
+
+static void
 source_registry_server_dispose (GObject *object)
 {
        ESourceRegistryServerPrivate *priv;
@@ -1047,23 +580,14 @@ source_registry_server_dispose (GObject *object)
                priv->main_context = NULL;
        }
 
-       if (priv->object_manager != NULL) {
-               g_object_unref (priv->object_manager);
-               priv->object_manager = NULL;
-       }
-
-       if (priv->source_manager != NULL) {
-               g_object_unref (priv->source_manager);
-               priv->source_manager = NULL;
-       }
+       g_clear_object (&priv->object_manager);
+       g_clear_object (&priv->source_manager);
+       g_clear_object (&priv->credentials_provider);
 
        g_hash_table_remove_all (priv->sources);
        g_hash_table_remove_all (priv->orphans);
        g_hash_table_remove_all (priv->monitors);
 
-       g_hash_table_remove_all (priv->running_auths);
-       g_hash_table_remove_all (priv->waiting_auths);
-
        /* Chain up to parent's dispose() method. */
        G_OBJECT_CLASS (e_source_registry_server_parent_class)->
                dispose (object);
@@ -1083,10 +607,6 @@ source_registry_server_finalize (GObject *object)
        g_mutex_clear (&priv->sources_lock);
        g_mutex_clear (&priv->orphans_lock);
 
-       g_mutex_clear (&priv->auth_lock);
-       g_hash_table_destroy (priv->running_auths);
-       g_hash_table_destroy (priv->waiting_auths);
-
        /* Chain up to parent's finalize() method. */
        G_OBJECT_CLASS (e_source_registry_server_parent_class)->
                finalize (object);
@@ -1116,9 +636,6 @@ source_registry_server_quit_server (EDBusServer *server,
 
        priv = E_SOURCE_REGISTRY_SERVER_GET_PRIVATE (server);
 
-       source_request_server_auth_request_cancel_all (
-               E_SOURCE_REGISTRY_SERVER (server));
-
        /* This makes the object manager unexport all objects. */
        g_dbus_object_manager_server_set_connection (
                priv->object_manager, NULL);
@@ -1273,6 +790,7 @@ e_source_registry_server_class_init (ESourceRegistryServerClass *class)
        g_type_class_add_private (class, sizeof (ESourceRegistryServerPrivate));
 
        object_class = G_OBJECT_CLASS (class);
+       object_class->constructed = source_registry_server_constructed;
        object_class->dispose = source_registry_server_dispose;
        object_class->finalize = source_registry_server_finalize;
 
@@ -1400,8 +918,6 @@ e_source_registry_server_init (ESourceRegistryServer *server)
        GHashTable *sources;
        GHashTable *orphans;
        GHashTable *monitors;
-       GHashTable *running_auths;
-       GHashTable *waiting_auths;
        const gchar *object_path;
 
        object_path = E_SOURCE_REGISTRY_SERVER_OBJECT_PATH;
@@ -1429,18 +945,6 @@ e_source_registry_server_init (ESourceRegistryServer *server)
                (GDestroyNotify) g_object_unref,
                (GDestroyNotify) g_object_unref);
 
-       running_auths = g_hash_table_new_full (
-               (GHashFunc) g_str_hash,
-               (GEqualFunc) g_str_equal,
-               (GDestroyNotify) g_free,
-               (GDestroyNotify) auth_request_unref);
-
-       waiting_auths = g_hash_table_new_full (
-               (GHashFunc) g_str_hash,
-               (GEqualFunc) g_str_equal,
-               (GDestroyNotify) g_free,
-               (GDestroyNotify) free_auth_queue);
-
        server->priv = E_SOURCE_REGISTRY_SERVER_GET_PRIVATE (server);
        server->priv->main_context = g_main_context_ref_thread_default ();
        server->priv->object_manager = object_manager;
@@ -1450,19 +954,6 @@ e_source_registry_server_init (ESourceRegistryServer *server)
        server->priv->monitors = monitors;
        g_mutex_init (&server->priv->sources_lock);
        g_mutex_init (&server->priv->orphans_lock);
-       g_mutex_init (&server->priv->auth_lock);
-       server->priv->waiting_auths = waiting_auths;
-       server->priv->running_auths = running_auths;
-
-       g_signal_connect (
-               source_manager, "handle-allow-auth-prompt-all",
-               G_CALLBACK (source_registry_server_allow_auth_prompt_all_cb),
-               server);
-
-       g_signal_connect (
-               source_manager, "handle-authenticate",
-               G_CALLBACK (source_registry_server_authenticate_cb),
-               server);
 
        g_signal_connect (
                source_manager, "handle-create-sources",
@@ -1491,6 +982,25 @@ e_source_registry_server_new (void)
 }
 
 /**
+ * e_source_registry_server_ref_credentials_provider:
+ * @server: an #ESourceRegistryServer
+ *
+ * Returns a referenced #ESourceRegistryCredentialsProvider.
+ *
+ * Returns: A referenced #ESourceRegistryCredentialsProvider. Unref it with
+ *    g_object_unref(), when no longer needed.
+ *
+ * Since: 3.14
+ **/
+ESourceCredentialsProvider *
+e_source_registry_server_ref_credentials_provider (ESourceRegistryServer *server)
+{
+       g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
+
+       return g_object_ref (server->priv->credentials_provider);
+}
+
+/**
  * e_source_registry_server_add_source:
  * @server: an #ESourceRegistryServer
  * @source: an #ESource
@@ -2320,187 +1830,3 @@ e_source_registry_server_ref_backend_factory (ESourceRegistryServer *server,
         * We specify this in source_registry_server_class_init(). */
        return E_COLLECTION_BACKEND_FACTORY (factory);
 }
-
-/**
- * e_source_registry_server_new_auth_session:
- * @server: an #ESourceRegistryServer
- * @authenticator: an #ESourceAuthenticator
- * @source_uid: a data source identifier
- *
- * Convenience function instantiates an appropriate authentication
- * session type for @source_uid.
- *
- * If @server has an #EServerSideSource instance for @source_uid, then
- * its #EServerSideSource:auth-session-type is used to instantiate a new
- * authentication session.  Otherwise a plain #EAuthenticationSession is
- * instantiated.
- *
- * Unreference the returned #EAuthenticationSession with g_object_unref()
- * when finished with it.
- *
- * Returns: a new #EAuthenticationSession for @source_uid
- *
- * Since: 3.8
- **/
-EAuthenticationSession *
-e_source_registry_server_new_auth_session (ESourceRegistryServer *server,
-                                           ESourceAuthenticator *authenticator,
-                                           const gchar *source_uid)
-{
-       GType auth_session_type = E_TYPE_AUTHENTICATION_SESSION;
-       ESource *source;
-
-       g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
-       g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATOR (authenticator), NULL);
-       g_return_val_if_fail (source_uid != NULL, NULL);
-
-       source = e_source_registry_server_ref_source (server, source_uid);
-       if (source != NULL) {
-               auth_session_type =
-                       e_server_side_source_get_auth_session_type (
-                       E_SERVER_SIDE_SOURCE (source));
-               g_object_unref (source);
-       }
-
-       g_return_val_if_fail (
-               g_type_is_a (
-                       auth_session_type,
-                       E_TYPE_AUTHENTICATION_SESSION), NULL);
-
-       return g_object_new (
-               auth_session_type,
-               "server", server,
-               "authenticator", authenticator,
-               "source-uid", source_uid, NULL);
-}
-
-/**
- * e_source_registry_server_authenticate_sync:
- * @server: an #ESourceRegistryServer
- * @session: an #EAuthenticationSession
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Queues the @session behind any ongoing or pending authentication
- * sessions for the same data source, and eventually executes @session
- * (see e_authentication_session_execute_sync() for more details).
- *
- * This function blocks until @session is finished executing.  For a
- * non-blocking variation see e_source_registry_server_authenticate().
- *
- * If an error occurs, the function sets @error and returns %FALSE.
- *
- * Returns: %TRUE on success, %FALSE on failure
- *
- * Since: 3.6
- **/
-gboolean
-e_source_registry_server_authenticate_sync (ESourceRegistryServer *server,
-                                            EAuthenticationSession *session,
-                                            GCancellable *cancellable,
-                                            GError **error)
-{
-       EAsyncClosure *closure;
-       GAsyncResult *result;
-       gboolean success;
-
-       g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), FALSE);
-       g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), FALSE);
-
-       closure = e_async_closure_new ();
-
-       e_source_registry_server_authenticate (
-               server, session, cancellable,
-               e_async_closure_callback, closure);
-
-       result = e_async_closure_wait (closure);
-
-       success = e_source_registry_server_authenticate_finish (
-               server, result, error);
-
-       e_async_closure_free (closure);
-
-       return success;
-}
-
-/**
- * e_source_registry_server_authenticate:
- * @server: an #ESourceRegistryServer
- * @session: an #EAuthenticationSession
- * @cancellable: optional #GCancellable object, or %NULL
- * @callback: a #GAsyncReadyCallback to call when the request is satisfied
- * @user_data: data to pass to the callback function
- *
- * Queues the @session behind any ongoing or pending authentication
- * sessions for the same data source, and eventually executes @session
- * (see e_authentication_session_execute_sync() for more details).
- *
- * This function returns immediately after enqueuing @session.  When
- * @session is finished executing, @callback will be called.  You can
- * then call e_source_registry_server_authenticate_finish() to get the
- * result of the operation.
- *
- * Since: 3.6
- **/
-void
-e_source_registry_server_authenticate (ESourceRegistryServer *server,
-                                       EAuthenticationSession *session,
-                                       GCancellable *cancellable,
-                                       GAsyncReadyCallback callback,
-                                       gpointer user_data)
-{
-       GSimpleAsyncResult *simple;
-       AuthRequest *request;
-       const gchar *uid;
-
-       g_return_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server));
-       g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
-
-       uid = e_authentication_session_get_source_uid (session);
-       g_return_if_fail (uid != NULL);
-
-       simple = g_simple_async_result_new (
-               G_OBJECT (server), callback, user_data,
-               e_source_registry_server_authenticate);
-
-       g_simple_async_result_set_check_cancellable (simple, cancellable);
-
-       request = auth_request_new (session, simple, cancellable);
-       source_registry_server_auth_request_push (server, uid, request);
-       auth_request_unref (request);
-
-       source_registry_server_maybe_start_auth_session (server, uid);
-
-       g_object_unref (simple);
-}
-
-/**
- * e_source_registry_server_authenticate_finish:
- * @server: an #ESourceRegistryServer
- * @result: a #GAsyncResult
- * @error: return location for a #GError, or %NULL
- *
- * Finishes the operation started with e_source_registry_server_authenticate().
- * If an error occurred, the function will set @error and return %FALSE.
- *
- * Returns: %TRUE on success, %FALSE on failure
- *
- * Since: 3.6
- **/
-gboolean
-e_source_registry_server_authenticate_finish (ESourceRegistryServer *server,
-                                              GAsyncResult *result,
-                                              GError **error)
-{
-       GSimpleAsyncResult *simple;
-
-       g_return_val_if_fail (
-               g_simple_async_result_is_valid (
-               result, G_OBJECT (server),
-               e_source_registry_server_authenticate), FALSE);
-
-       simple = G_SIMPLE_ASYNC_RESULT (result);
-
-       /* Assume success unless a GError is set. */
-       return !g_simple_async_result_propagate_error (simple, error);
-}
diff --git a/libebackend/e-source-registry-server.h b/libebackend/e-source-registry-server.h
index 44d7ee6..d86b100 100644
--- a/libebackend/e-source-registry-server.h
+++ b/libebackend/e-source-registry-server.h
@@ -24,7 +24,6 @@
 
 #include <libedataserver/libedataserver.h>
 
-#include <libebackend/e-authentication-session.h>
 #include <libebackend/e-backend-enums.h>
 #include <libebackend/e-data-factory.h>
 #include <libebackend/e-collection-backend.h>
@@ -109,6 +108,9 @@ struct _ESourceRegistryServerClass {
 GType          e_source_registry_server_get_type
                                                (void) G_GNUC_CONST;
 EDBusServer *  e_source_registry_server_new    (void);
+ESourceCredentialsProvider *
+               e_source_registry_server_ref_credentials_provider
+                                               (ESourceRegistryServer *server);
 void           e_source_registry_server_add_source
                                                (ESourceRegistryServer *server,
                                                 ESource *source);
@@ -153,26 +155,6 @@ ECollectionBackendFactory *
                e_source_registry_server_ref_backend_factory
                                                (ESourceRegistryServer *server,
                                                 ESource *source);
-EAuthenticationSession *
-               e_source_registry_server_new_auth_session
-                                               (ESourceRegistryServer *server,
-                                                ESourceAuthenticator *authenticator,
-                                                const gchar *source_uid);
-gboolean       e_source_registry_server_authenticate_sync
-                                               (ESourceRegistryServer *server,
-                                                EAuthenticationSession *session,
-                                                GCancellable *cancellable,
-                                                GError **error);
-void           e_source_registry_server_authenticate
-                                               (ESourceRegistryServer *server,
-                                                EAuthenticationSession *session,
-                                                GCancellable *cancellable,
-                                                GAsyncReadyCallback callback,
-                                                gpointer user_data);
-gboolean       e_source_registry_server_authenticate_finish
-                                               (ESourceRegistryServer *server,
-                                                GAsyncResult *result,
-                                                GError **error);
 
 #ifndef EDS_DISABLE_DEPRECATED
 gboolean       e_source_registry_server_load_all
diff --git a/libebackend/e-subprocess-factory.c b/libebackend/e-subprocess-factory.c
index 1fbca51..2fa077e 100644
--- a/libebackend/e-subprocess-factory.c
+++ b/libebackend/e-subprocess-factory.c
@@ -28,9 +28,9 @@
 
 #include <glib/gi18n-lib.h>
 
-#include <libebackend/e-extensible.h>
+#include <libedataserver/libedataserver.h>
+
 #include <libebackend/e-backend-factory.h>
-#include <libebackend/e-module.h>
 
 #include <e-dbus-subprocess-backend.h>
 
diff --git a/libebackend/libebackend.h b/libebackend/libebackend.h
index f4f6feb..c0fa01c 100644
--- a/libebackend/libebackend.h
+++ b/libebackend/libebackend.h
@@ -22,8 +22,6 @@
 
 #include <libedataserver/libedataserver.h>
 
-#include <libebackend/e-authentication-mediator.h>
-#include <libebackend/e-authentication-session.h>
 #include <libebackend/e-backend-enums.h>
 #include <libebackend/e-backend-enumtypes.h>
 #include <libebackend/e-backend-factory.h>
@@ -32,10 +30,7 @@
 #include <libebackend/e-collection-backend.h>
 #include <libebackend/e-data-factory.h>
 #include <libebackend/e-dbus-server.h>
-#include <libebackend/e-extensible.h>
-#include <libebackend/e-extension.h>
 #include <libebackend/e-file-cache.h>
-#include <libebackend/e-module.h>
 #include <libebackend/e-oauth2-support.h>
 #include <libebackend/e-offline-listener.h>
 #include <libebackend/e-server-side-source.h>
diff --git a/libedataserver/Makefile.am b/libedataserver/Makefile.am
index c41474e..b3396dd 100644
--- a/libedataserver/Makefile.am
+++ b/libedataserver/Makefile.am
@@ -29,6 +29,7 @@ SHARED_COMPILER_FLAGS = \
        -DE_DATA_SERVER_LOCALEDIR=\""$(localedir)"\" \
        -DE_DATA_SERVER_EXTENSIONDIR=\"$(extensiondir)\" \
        -DE_DATA_SERVER_IMAGESDIR=\"$(imagesdir)\" \
+       -DE_DATA_SERVER_CREDENTIALMODULEDIR=\"$(credentialmoduledir)\" \
        -DE_DATA_SERVER_PRIVDATADIR=\"$(privdatadir)\" \
        -DE_DATA_SERVER_UI_UIDIR=\""$(uidir)"\" \
        $(E_DATA_SERVER_CFLAGS) \
@@ -52,6 +53,8 @@ libedataserver_1_2_la_SOURCES = \
        e-client-private.h \
        e-collator.c \
        e-credentials.c \
+       e-extensible.c \
+       e-extension.c \
        e-flag.c \
        e-free-form-exp.c \
        e-gdbus-templates.c \
@@ -59,6 +62,7 @@ libedataserver_1_2_la_SOURCES = \
        e-list.c \
        e-list-iterator.c \
        e-memory.c \
+       e-module.c \
        e-operation-pool.c \
        e-proxy.c \
        e-sexp.c \
@@ -67,12 +71,14 @@ libedataserver_1_2_la_SOURCES = \
        e-source-address-book.c \
        e-source-alarms.c \
        e-source-authentication.c \
-       e-source-authenticator.c \
        e-source-autocomplete.c \
        e-source-backend.c \
        e-source-calendar.c \
        e-source-camel.c \
        e-source-collection.c \
+       e-source-credentials-provider.c \
+       e-source-credentials-provider-impl.c \
+       e-source-credentials-provider-impl-password.c \
        e-source-goa.c \
        e-source-mail-account.c \
        e-source-mail-composition.c \
@@ -131,6 +137,8 @@ libedataserverinclude_HEADERS = \
        e-client.h \
        e-collator.h \
        e-credentials.h \
+       e-extensible.h \
+       e-extension.h \
        e-flag.h \
        e-free-form-exp.h \
        e-gdbus-templates.h \
@@ -138,6 +146,7 @@ libedataserverinclude_HEADERS = \
        e-list.h \
        e-list-iterator.h \
        e-memory.h \
+       e-module.h \
        e-operation-pool.h \
        e-proxy.h \
        e-sexp.h \
@@ -145,12 +154,14 @@ libedataserverinclude_HEADERS = \
        e-source-address-book.h \
        e-source-alarms.h \
        e-source-authentication.h \
-       e-source-authenticator.h \
        e-source-autocomplete.h \
        e-source-backend.h \
        e-source-calendar.h \
        e-source-camel.h \
        e-source-collection.h \
+       e-source-credentials-provider.h \
+       e-source-credentials-provider-impl.h \
+       e-source-credentials-provider-impl-password.h \
        e-source-enums.h \
        e-source-enumtypes.h \
        e-source-extension.h \
diff --git a/libedataserver/e-client.c b/libedataserver/e-client.c
index 901724b..d2ad89d 100644
--- a/libedataserver/e-client.c
+++ b/libedataserver/e-client.c
@@ -43,6 +43,8 @@
 
 #include <libedataserver/e-data-server-util.h>
 
+#include "e-flag.h"
+
 #include "e-client.h"
 #include "e-client-private.h"
 
@@ -1844,6 +1846,294 @@ e_client_refresh_sync (EClient *client,
        return class->refresh_sync (client, cancellable, error);
 }
 
+static void
+client_wait_for_connected_thread (GTask *task,
+                                 gpointer source_object,
+                                 gpointer task_data,
+                                 GCancellable *cancellable)
+{
+       guint32 timeout_seconds;
+       gboolean success;
+       GError *local_error = NULL;
+
+       timeout_seconds = GPOINTER_TO_UINT (task_data);
+       success = e_client_wait_for_connected_sync (E_CLIENT (source_object), timeout_seconds, cancellable, 
&local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
+}
+
+/**
+ * e_client_wait_for_connected:
+ * @client: an #EClient
+ * @timeout_seconds: a timeout for the wait, in seconds
+ * @cancellable: (allow none): a #GCancellable; or %NULL
+ * @callback: callback to call when a result is ready
+ * @user_data: user data for the @callback
+ *
+ * Asynchronously waits until the @client is connected (according
+ * to @ESource::connection-status property), but not longer than @timeout_seconds.
+ *
+ * The call is finished by e_client_wait_for_connected_finish() from
+ * the @callback.
+ *
+ * Since: 3.14
+ **/
+void
+e_client_wait_for_connected (EClient *client,
+                            guint32 timeout_seconds,
+                            GCancellable *cancellable,
+                            GAsyncReadyCallback callback,
+                            gpointer user_data)
+{
+       GTask *task;
+
+       g_return_if_fail (E_IS_CLIENT (client));
+
+       task = g_task_new (client, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_client_wait_for_connected);
+       g_task_set_task_data (task, GUINT_TO_POINTER (timeout_seconds), NULL);
+
+       g_task_run_in_thread (task, client_wait_for_connected_thread);
+
+       g_object_unref (task);
+}
+
+/**
+ * e_client_wait_for_connected_finish:
+ * @client: an #EClient
+ * @result: a #GAsyncResult
+ * @error: (out): (allow none): a #GError to set an error, or %NULL
+ *
+ * Finishes previous call of e_client_wait_for_connected().
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_client_wait_for_connected_finish (EClient *client,
+                                   GAsyncResult *result,
+                                   GError **error)
+{
+       g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, client), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_client_wait_for_connected), FALSE);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+client_wait_for_connected_cancelled_cb (GCancellable *cancellable,
+                                       EFlag *flag)
+{
+       g_return_if_fail (flag != NULL);
+
+       e_flag_set (flag);
+}
+
+static void
+client_wait_for_connected_notify_cb (ESource *source,
+                                    GParamSpec *param,
+                                    EFlag *flag)
+{
+       g_return_if_fail (flag != NULL);
+
+       if (e_source_get_connection_status (source) == E_SOURCE_CONNECTION_STATUS_CONNECTED)
+               e_flag_set (flag);
+}
+
+/**
+ * @client: an #EClient
+ * @timeout_seconds: a timeout for the wait, in seconds
+ * @cancellable: (allow none): a #GCancellable; or %NULL
+ * @callback: callback to call when a result is ready
+ * @error: (out): (allow none): a #GError to set an error, or %NULL
+ *
+ * Synchronously waits until the @client is connected (according
+ * to @ESource::connection-status property), but not longer than @timeout_seconds.
+ *
+ * Note: This also calls e_client_retrieve_properties_sync() on success, to have
+ *   up-to-date property values on the client side, without a delay due
+ *   to property change notifcations delivery through D-Bus.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_client_wait_for_connected_sync (EClient *client,
+                                 guint32 timeout_seconds,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       ESource *source;
+       EFlag *flag;
+       gulong cancellable_handler_id = 0, notify_handler_id;
+       gint64 end_time;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+
+       end_time = g_get_monotonic_time () + timeout_seconds * G_TIME_SPAN_SECOND;
+       flag = e_flag_new ();
+
+       if (cancellable)
+               cancellable_handler_id = g_cancellable_connect (cancellable,
+                       G_CALLBACK (client_wait_for_connected_cancelled_cb), flag, NULL);
+
+       source = e_client_get_source (client);
+
+       notify_handler_id = g_signal_connect (source, "notify::connection-status",
+               G_CALLBACK (client_wait_for_connected_notify_cb), flag);
+
+       while (success = e_source_get_connection_status (source) == E_SOURCE_CONNECTION_STATUS_CONNECTED,
+              !success && !g_cancellable_is_cancelled (cancellable)) {
+               e_flag_clear (flag);
+
+               if (timeout_seconds > 0) {
+                       if (g_get_monotonic_time () > end_time)
+                               break;
+
+                       e_flag_wait_until (flag, end_time);
+               } else {
+                       e_flag_wait (flag);
+               }
+       }
+
+       if (cancellable_handler_id > 0 && cancellable)
+               g_cancellable_disconnect (cancellable, cancellable_handler_id);
+
+       g_signal_handler_disconnect (source, notify_handler_id);
+       e_flag_set (flag);
+       e_flag_free (flag);
+
+       success = e_source_get_connection_status (source) == E_SOURCE_CONNECTION_STATUS_CONNECTED;
+
+       if (!success && !g_cancellable_set_error_if_cancelled (cancellable, error))
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, _("Timeout was reached"));
+       else if (success)
+               success = e_client_retrieve_properties_sync (client, cancellable, error);
+
+       return success;
+}
+
+/**
+ * e_client_retrieve_properties_sync:
+ * @client: an #EClient
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @error: (allow none): return location for a #GError, or %NULL
+ *
+ * Retrieves @client properties to match server-side values, without waiting
+ * for the D-Bus property change notifications delivery.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_client_retrieve_properties_sync (EClient *client,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+       EClientClass *klass;
+
+       g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+
+       klass = E_CLIENT_GET_CLASS (client);
+       g_return_val_if_fail (klass != NULL, FALSE);
+       g_return_val_if_fail (klass->retrieve_properties_sync != NULL, FALSE);
+
+       return klass->retrieve_properties_sync (client, cancellable, error);
+}
+
+static void
+client_retrieve_properties_thread (GTask *task,
+                                  gpointer source_object,
+                                  gpointer task_data,
+                                  GCancellable *cancellable)
+{
+       gboolean success;
+       GError *local_error = NULL;
+
+       success = e_client_retrieve_properties_sync (E_CLIENT (source_object), cancellable, &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
+}
+
+/**
+ * e_client_retrieve_properties:
+ * @client: an #EClient
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously retrieves @client properties to match server-side values,
+ * without waiting for the D-Bus property change notifications delivery.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_client_retrieve_properties_finish() to get the result of the operation.
+ *
+ * Since: 3.14
+ **/
+void
+e_client_retrieve_properties (EClient *client,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+       GTask *task;
+
+       g_return_if_fail (E_IS_CLIENT (client));
+
+       task = g_task_new (client, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_client_retrieve_properties);
+
+       g_task_run_in_thread (task, client_retrieve_properties_thread);
+
+       g_object_unref (task);
+}
+
+/**
+ * e_client_retrieve_properties_finish:
+ * @client: an #EClient
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Finishes the operation started with e_client_retrieve_properties().
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_client_retrieve_properties_finish (EClient *client,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
+       g_return_val_if_fail (E_IS_CLIENT (client), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, client), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_client_retrieve_properties), FALSE);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
 /**
  * e_client_util_slist_to_strv:
  * @strings: (element-type utf8): a #GSList of strings (const gchar *)
diff --git a/libedataserver/e-client.h b/libedataserver/e-client.h
index a808e0f..d421671 100644
--- a/libedataserver/e-client.h
+++ b/libedataserver/e-client.h
@@ -266,6 +266,10 @@ struct _EClientClass {
        gboolean        (*refresh_sync)         (EClient *client,
                                                 GCancellable *cancellable,
                                                 GError **error);
+       gboolean        (*retrieve_properties_sync)
+                                               (EClient *client,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
        void            (*opened)               (EClient *client,
                                                 const GError *error);
@@ -318,6 +322,20 @@ gboolean   e_client_refresh_sync           (EClient *client,
                                                 GCancellable *cancellable,
                                                 GError **error);
 
+void           e_client_wait_for_connected     (EClient *client,
+                                                guint32 timeout_seconds,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_client_wait_for_connected_finish
+                                               (EClient *client,
+                                                GAsyncResult *result,
+                                                GError **error);
+gboolean       e_client_wait_for_connected_sync(EClient *client,
+                                                guint32 timeout_seconds,
+                                                GCancellable *cancellable,
+                                                GError **error);
+
 GSList *       e_client_util_parse_comma_strings
                                                (const gchar *strings);
 
@@ -407,6 +425,18 @@ gboolean   e_client_remove_finish          (EClient *client,
 gboolean       e_client_remove_sync            (EClient *client,
                                                 GCancellable *cancellable,
                                                 GError **error);
+gboolean       e_client_retrieve_properties_sync
+                                               (EClient *client,
+                                                GCancellable *cancellable,
+                                                GError **error);
+void           e_client_retrieve_properties    (EClient *client,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_client_retrieve_properties_finish
+                                               (EClient *client,
+                                                GAsyncResult *result,
+                                                GError **error);
 gchar **       e_client_util_slist_to_strv     (const GSList *strings);
 GSList *       e_client_util_strv_to_slist     (const gchar * const *strv);
 GSList *       e_client_util_copy_string_slist (GSList *copy_to,
diff --git a/libedataserver/e-data-server-util.c b/libedataserver/e-data-server-util.c
index c0456e5..6d7ee7f 100644
--- a/libedataserver/e-data-server-util.c
+++ b/libedataserver/e-data-server-util.c
@@ -32,6 +32,8 @@
 
 #include <glib-object.h>
 
+#include "e-source-enumtypes.h"
+
 #include "e-data-server-util.h"
 
 /**
@@ -1090,6 +1092,27 @@ e_util_free_nullable_object_slist (GSList *objects)
 }
 
 /**
+ * e_util_safe_free_string:
+ * @str: a string to free
+ *
+ * Calls g_free() on @string, but before it rewrites its content with zeros.
+ * This is suitable to free strings with passwords.
+ *
+ * Since: 3.14
+ **/
+void
+e_util_safe_free_string (gchar *str)
+{
+       if (!str)
+               return;
+
+       if (*str)
+               memset (str, 0, sizeof (gchar) * strlen (str));
+
+       g_free (str);
+}
+
+/**
  * e_queue_transfer:
  * @src_queue: a source #GQueue
  * @dst_queue: a destination #GQueue
@@ -1650,6 +1673,7 @@ static const gchar *localedir;
 static const gchar *extensiondir;
 static const gchar *imagesdir;
 static const gchar *ui_uidir;
+static const gchar *credentialmoduledir;
 
 static HMODULE hmodule;
 G_LOCK_DEFINE_STATIC (mutex);
@@ -1731,6 +1755,7 @@ setup (void)
        extensiondir = replace_prefix (prefix, E_DATA_SERVER_EXTENSIONDIR);
        imagesdir = replace_prefix (prefix, E_DATA_SERVER_IMAGESDIR);
        ui_uidir = replace_prefix (prefix, E_DATA_SERVER_UI_UIDIR);
+       credentialmoduledir = replace_prefix (prefix, E_DATA_SERVER_CREDENTIALMODULEDIR);
 
        G_UNLOCK (mutex);
 }
@@ -1756,6 +1781,7 @@ e_util_get_##varbl (void) \
 PRIVATE_GETTER (extensiondir)
 PRIVATE_GETTER (imagesdir)
 PRIVATE_GETTER (ui_uidir)
+PRIVATE_GETTER (credentialmoduledir);
 
 PUBLIC_GETTER (prefix)
 PUBLIC_GETTER (cp_prefix)
@@ -1904,7 +1930,7 @@ e_data_server_util_get_dbus_call_timeout (void)
 ENamedParameters *
 e_named_parameters_new (void)
 {
-       return (ENamedParameters *) g_ptr_array_new_with_free_func (g_free);
+       return (ENamedParameters *) g_ptr_array_new_with_free_func ((GDestroyNotify) e_util_safe_free_string);
 }
 
 /**
@@ -1940,6 +1966,34 @@ e_named_parameters_new_strv (const gchar * const *strv)
 }
 
 /**
+ * e_named_parameters_new_clone:
+ * @parameters: an #ENamedParameters to be used as a content of a newly
+ *    created #ENamedParameters
+ *
+ * Creates a new instance of an #ENamedParameters, with initial content
+ * being taken from @parameters. This should be freed with e_named_parameters_free(),
+ * when no longer needed. Names are compared case insensitively.
+ *
+ * The structure is not thread safe, if the caller requires thread safety,
+ * then it should provide it on its own.
+ *
+ * Returns: newly allocated #ENamedParameters
+ *
+ * Since: 3.14
+ **/
+ENamedParameters *
+e_named_parameters_new_clone (const ENamedParameters *parameters)
+{
+       ENamedParameters *clone;
+
+       clone = e_named_parameters_new ();
+       if (parameters)
+               e_named_parameters_assign (clone, parameters);
+
+       return clone;
+}
+
+/**
  * e_named_parameters_free:
  * @parameters: an #ENamedParameters
  *
@@ -2395,3 +2449,46 @@ e_source_registry_debug_print (const gchar *format,
 
        g_string_free (str, TRUE);
 }
+
+/**
+ * e_type_traverse:
+ * @parent_type: the root #GType to traverse from
+ * @func: the function to call for each visited #GType
+ * @user_data: user data to pass to the function
+ *
+ * Calls @func for all instantiable subtypes of @parent_type.
+ *
+ * This is often useful for extending functionality by way of #EModule.
+ * A module may register a subtype of @parent_type in its e_module_load()
+ * function.  Then later on the application will call e_type_traverse()
+ * to instantiate all registered subtypes of @parent_type.
+ *
+ * Since: 3.4
+ **/
+void
+e_type_traverse (GType parent_type,
+                 ETypeFunc func,
+                 gpointer user_data)
+{
+       GType *children;
+       guint n_children, ii;
+
+       g_return_if_fail (func != NULL);
+
+       children = g_type_children (parent_type, &n_children);
+
+       for (ii = 0; ii < n_children; ii++) {
+               GType type = children[ii];
+
+               /* Recurse over the child's children. */
+               e_type_traverse (type, func, user_data);
+
+               /* Skip abstract types. */
+               if (G_TYPE_IS_ABSTRACT (type))
+                       continue;
+
+               func (type, user_data);
+       }
+
+       g_free (children);
+}
diff --git a/libedataserver/e-data-server-util.h b/libedataserver/e-data-server-util.h
index 065d063..7cd34b3 100644
--- a/libedataserver/e-data-server-util.h
+++ b/libedataserver/e-data-server-util.h
@@ -29,6 +29,8 @@
 #include <sys/types.h>
 #include <gio/gio.h>
 
+#include <libedataserver/e-source-enums.h>
+
 G_BEGIN_DECLS
 
 struct tm;
@@ -77,6 +79,8 @@ gchar **      e_util_slist_to_strv            (const GSList *strings);
 GSList *       e_util_strv_to_slist            (const gchar * const *strv);
 void           e_util_free_nullable_object_slist
                                                (GSList *objects);
+void           e_util_safe_free_string         (gchar *str);
+
 void           e_queue_transfer                (GQueue *src_queue,
                                                 GQueue *dst_queue);
 GWeakRef *     e_weak_ref_new                  (gpointer object);
@@ -141,11 +145,15 @@ void              e_util_win32_initialize         (void);
 struct _ENamedParameters;
 typedef struct _ENamedParameters ENamedParameters;
 
+#define E_TYPE_NAMED_PARAMETERS (e_named_parameters_get_type ())
+
 GType           e_named_parameters_get_type     (void) G_GNUC_CONST;
 ENamedParameters *
                e_named_parameters_new          (void);
 ENamedParameters *
                e_named_parameters_new_strv     (const gchar * const *strv);
+ENamedParameters *
+               e_named_parameters_new_clone    (const ENamedParameters *parameters);
 void           e_named_parameters_free         (ENamedParameters *parameters);
 void           e_named_parameters_clear        (ENamedParameters *parameters);
 void           e_named_parameters_assign       (ENamedParameters *parameters,
@@ -216,6 +224,21 @@ gboolean   e_source_registry_debug_enabled (void);
 void           e_source_registry_debug_print   (const gchar *format,
                                                 ...) G_GNUC_PRINTF (1, 2);
 
+/**
+ * ETypeFunc:
+ * @type: a #GType
+ * @user_data: user data passed to e_type_traverse()
+ *
+ * Specifies the type of functions passed to e_type_traverse().
+ *
+ * Since: 3.4
+ **/
+typedef void   (*ETypeFunc)                    (GType type,
+                                                gpointer user_data);
+void           e_type_traverse                 (GType parent_type,
+                                                ETypeFunc func,
+                                                gpointer user_data);
+
 G_END_DECLS
 
 #endif /* E_DATA_SERVER_UTIL_H */
diff --git a/libebackend/e-extensible.c b/libedataserver/e-extensible.c
similarity index 96%
rename from libebackend/e-extensible.c
rename to libedataserver/e-extensible.c
index eec96c8..fb57705 100644
--- a/libebackend/e-extensible.c
+++ b/libedataserver/e-extensible.c
@@ -17,7 +17,7 @@
 
 /**
  * SECTION: e-extensible
- * @include: libebackend/libebackend.h
+ * @include: libedataserver/libedataserver.h
  * @short_description: An interface for extending objects
  *
  * #EExtension objects can be tacked on to any #GObject instance that
@@ -29,7 +29,7 @@
  *
  * <informalexample>
  * <programlisting>
- * #include <libebackend/libebackend.h>
+ * #include <libedataserver/libedataserver.h>
  *
  * G_DEFINE_TYPE_WITH_CODE (
  *         ECustomWidget, e_custom_widget, GTK_TYPE_WIDGET,
@@ -55,11 +55,14 @@
  * </informalexample>
  **/
 
-#include "e-extensible.h"
-
+#ifdef HAVE_CONFIG_H
 #include <config.h>
-#include <libebackend/e-extension.h>
-#include <libebackend/e-module.h>
+#endif
+
+#include "e-extension.h"
+#include "e-data-server-util.h"
+
+#include "e-extensible.h"
 
 #define IS_AN_EXTENSION_TYPE(type) \
        (g_type_is_a ((type), E_TYPE_EXTENSION))
diff --git a/libebackend/e-extensible.h b/libedataserver/e-extensible.h
similarity index 91%
rename from libebackend/e-extensible.h
rename to libedataserver/e-extensible.h
index 3f358f2..383d89a 100644
--- a/libebackend/e-extensible.h
+++ b/libedataserver/e-extensible.h
@@ -15,8 +15,8 @@
  *
  */
 
-#if !defined (__LIBEBACKEND_H_INSIDE__) && !defined (LIBEBACKEND_COMPILATION)
-#error "Only <libebackend/libebackend.h> should be included directly."
+#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
+#error "Only <libedataserver/libedataserver.h> should be included directly."
 #endif
 
 #ifndef E_EXTENSIBLE_H
diff --git a/libebackend/e-extension.c b/libedataserver/e-extension.c
similarity index 98%
rename from libebackend/e-extension.c
rename to libedataserver/e-extension.c
index 9358a30..020e4a9 100644
--- a/libebackend/e-extension.c
+++ b/libedataserver/e-extension.c
@@ -17,7 +17,7 @@
 
 /**
  * SECTION: e-extension
- * @include: libebackend/libebackend.h
+ * @include: libedataserver/libedataserver.h
  * @short_description: An abstract base class for extensions
  *
  * #EExtension provides a way to extend the functionality of objects
@@ -38,9 +38,11 @@
  *    registered in the library module's e_module_load() function.
  **/
 
-#include "e-extension.h"
-
+#ifdef HAVE_CONFIG_H
 #include <config.h>
+#endif
+
+#include "e-extension.h"
 
 #define E_EXTENSION_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
diff --git a/libebackend/e-extension.h b/libedataserver/e-extension.h
similarity index 90%
rename from libebackend/e-extension.h
rename to libedataserver/e-extension.h
index f271ded..d75900b 100644
--- a/libebackend/e-extension.h
+++ b/libedataserver/e-extension.h
@@ -15,14 +15,14 @@
  *
  */
 
-#if !defined (__LIBEBACKEND_H_INSIDE__) && !defined (LIBEBACKEND_COMPILATION)
-#error "Only <libebackend/libebackend.h> should be included directly."
+#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
+#error "Only <libedataserver/libedataserver.h> should be included directly."
 #endif
 
 #ifndef E_EXTENSION_H
 #define E_EXTENSION_H
 
-#include <libebackend/e-extensible.h>
+#include <libedataserver/e-extensible.h>
 
 /* Standard GObject macros */
 #define E_TYPE_EXTENSION \
diff --git a/libebackend/e-module.c b/libedataserver/e-module.c
similarity index 87%
rename from libebackend/e-module.c
rename to libedataserver/e-module.c
index c5c81f2..feb0c14 100644
--- a/libebackend/e-module.c
+++ b/libedataserver/e-module.c
@@ -17,14 +17,17 @@
 
 /**
  * SECTION: e-module
- * @include: libebackend/libebackend.h
+ * @include: libedataserver/libedataserver.h
  * @short_description: A module loader
  **/
 
-#include "e-module.h"
-
+#ifdef HAVE_CONFIG_H
 #include <config.h>
-#include <glib/gi18n.h>
+#endif
+
+#include <glib.h>
+
+#include "e-module.h"
 
 #define E_MODULE_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -341,47 +344,3 @@ e_module_load_file (const gchar *filename)
 
        return module;
 }
-
-/**
- * e_type_traverse:
- * @parent_type: the root #GType to traverse from
- * @func: the function to call for each visited #GType
- * @user_data: user data to pass to the function
- *
- * Calls @func for all instantiable subtypes of @parent_type.
- *
- * This is often useful for extending functionality by way of #EModule.
- * A module may register a subtype of @parent_type in its e_module_load()
- * function.  Then later on the application will call e_type_traverse()
- * to instantiate all registered subtypes of @parent_type.
- *
- * Since: 3.4
- **/
-void
-e_type_traverse (GType parent_type,
-                 ETypeFunc func,
-                 gpointer user_data)
-{
-       GType *children;
-       guint n_children, ii;
-
-       g_return_if_fail (func != NULL);
-
-       children = g_type_children (parent_type, &n_children);
-
-       for (ii = 0; ii < n_children; ii++) {
-               GType type = children[ii];
-
-               /* Recurse over the child's children. */
-               e_type_traverse (type, func, user_data);
-
-               /* Skip abstract types. */
-               if (G_TYPE_IS_ABSTRACT (type))
-                       continue;
-
-               func (type, user_data);
-       }
-
-       g_free (children);
-}
-
diff --git a/libebackend/e-module.h b/libedataserver/e-module.h
similarity index 78%
rename from libebackend/e-module.h
rename to libedataserver/e-module.h
index af6471e..d4495eb 100644
--- a/libebackend/e-module.h
+++ b/libedataserver/e-module.h
@@ -15,8 +15,8 @@
  *
  */
 
-#if !defined (__LIBEBACKEND_H_INSIDE__) && !defined (LIBEBACKEND_COMPILATION)
-#error "Only <libebackend/libebackend.h> should be included directly."
+#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
+#error "Only <libedataserver/libedataserver.h> should be included directly."
 #endif
 
 #ifndef E_MODULE_H
@@ -73,23 +73,6 @@ const gchar *        e_module_get_filename           (EModule *module);
 EModule *      e_module_load_file              (const gchar *filename);
 GList *                e_module_load_all_in_directory  (const gchar *dirname);
 
-/* This is here for lack of a better place for it. */
-
-/**
- * ETypeFunc:
- * @type: a #GType
- * @user_data: user data passed to e_type_traverse()
- *
- * Specifies the type of functions passed to e_type_traverse().
- *
- * Since: 3.4
- **/
-typedef void   (*ETypeFunc)                    (GType type,
-                                                gpointer user_data);
-void           e_type_traverse                 (GType parent_type,
-                                                ETypeFunc func,
-                                                gpointer user_data);
-
 G_END_DECLS
 
 #endif /* E_MODULE_H */
diff --git a/libedataserver/e-source-authentication.c b/libedataserver/e-source-authentication.c
index 1d4c422..b648a9d 100644
--- a/libedataserver/e-source-authentication.c
+++ b/libedataserver/e-source-authentication.c
@@ -50,6 +50,7 @@ struct _ESourceAuthenticationPrivate {
        gchar *proxy_uid;
        gboolean remember_password;
        gchar *user;
+       gchar *credential_name;
 
        /* GNetworkAddress caches data internally, so we maintain the
         * instance to preserve the cache as opposed to just creating
@@ -65,7 +66,8 @@ enum {
        PROP_PORT,
        PROP_PROXY_UID,
        PROP_REMEMBER_PASSWORD,
-       PROP_USER
+       PROP_USER,
+       PROP_CREDENTIAL_NAME
 };
 
 G_DEFINE_TYPE (
@@ -135,6 +137,12 @@ source_authentication_set_property (GObject *object,
                                E_SOURCE_AUTHENTICATION (object),
                                g_value_get_string (value));
                        return;
+
+               case PROP_CREDENTIAL_NAME:
+                       e_source_authentication_set_credential_name (
+                               E_SOURCE_AUTHENTICATION (object),
+                               g_value_get_string (value));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -195,6 +203,13 @@ source_authentication_get_property (GObject *object,
                                e_source_authentication_dup_user (
                                E_SOURCE_AUTHENTICATION (object)));
                        return;
+
+               case PROP_CREDENTIAL_NAME:
+                       g_value_take_string (
+                               value,
+                               e_source_authentication_dup_credential_name (
+                               E_SOURCE_AUTHENTICATION (object)));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -338,6 +353,21 @@ e_source_authentication_class_init (ESourceAuthenticationClass *class)
                        G_PARAM_CONSTRUCT |
                        G_PARAM_STATIC_STRINGS |
                        E_SOURCE_PARAM_SETTING));
+
+       /* An empty string or NULL means to use E_SOURCE_CREDENTIAL_PASSWORD to pass
+          the stored "password" into the backend with e_source_invoke_authenticate()/_sync() */
+       g_object_class_install_property (
+               object_class,
+               PROP_CREDENTIAL_NAME,
+               g_param_spec_string (
+                       "credential-name",
+                       "Credential Name",
+                       "What name to use for the authentication method in credentials for authentication",
+                       NULL,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS |
+                       E_SOURCE_PARAM_SETTING));
 }
 
 static void
@@ -844,3 +874,92 @@ e_source_authentication_set_user (ESourceAuthentication *extension,
 
        g_object_notify (G_OBJECT (extension), "user");
 }
+
+/**
+ * e_source_authentication_get_credential_name:
+ * @extension: an #ESourceAuthentication
+ *
+ * Returns the credential name used to pass the stored or gathered credential
+ * (like password) into the e_source_invoke_authenticate(). This is
+ * a counterpart of the authentication method. The %NULL means to use
+ * the default name, which is #E_SOURCE_CREDENTIAL_PASSWORD.
+ *
+ * Returns: the credential name to use for authentication, or %NULL
+ *
+ * Since: 3.14
+ **/
+const gchar *
+e_source_authentication_get_credential_name (ESourceAuthentication *extension)
+{
+       g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+       return extension->priv->credential_name;
+}
+
+/**
+ * e_source_authentication_dup_credential_name:
+ * @extension: an #ESourceAuthentication
+ *
+ * Thread-safe variation of e_source_authentication_get_credential_name().
+ * Use this function when accessing @extension from multiple threads.
+ *
+ * The returned string should be freed with g_free() when no longer needed.
+ *
+ * Returns: a newly-allocated copy of #ESourceAuthentication:credential-name
+ *
+ * Since: 3.14
+ **/
+gchar *
+e_source_authentication_dup_credential_name (ESourceAuthentication *extension)
+{
+       const gchar *protected;
+       gchar *duplicate;
+
+       g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATION (extension), NULL);
+
+       g_mutex_lock (&extension->priv->property_lock);
+
+       protected = e_source_authentication_get_credential_name (extension);
+       duplicate = g_strdup (protected);
+
+       g_mutex_unlock (&extension->priv->property_lock);
+
+       return duplicate;
+}
+
+/**
+ * e_source_authentication_set_credential_name:
+ * @extension: an #ESourceAuthentication
+ * @credential_name: (allow-none): a credential name, or %NULL
+ *
+ * Sets the credential name used to pass the stored or gathered credential
+ * (like password) into the e_source_invoke_authenticate(). This is
+ * a counterpart of the authentication method. The %NULL means to use
+ * the default name, which is #E_SOURCE_CREDENTIAL_PASSWORD.
+ *
+ * The internal copy of @credential_name is automatically stripped
+ * of leading and trailing whitespace. If the resulting string is
+ * empty, %NULL is set instead.
+ *
+ * Since: 3.14
+ **/
+void
+e_source_authentication_set_credential_name (ESourceAuthentication *extension,
+                                            const gchar *credential_name)
+{
+       g_return_if_fail (E_IS_SOURCE_AUTHENTICATION (extension));
+
+       g_mutex_lock (&extension->priv->property_lock);
+
+       if (g_strcmp0 (extension->priv->credential_name, credential_name) == 0) {
+               g_mutex_unlock (&extension->priv->property_lock);
+               return;
+       }
+
+       g_free (extension->priv->credential_name);
+       extension->priv->credential_name = e_util_strdup_strip (credential_name);
+
+       g_mutex_unlock (&extension->priv->property_lock);
+
+       g_object_notify (G_OBJECT (extension), "credential-name");
+}
diff --git a/libedataserver/e-source-authentication.h b/libedataserver/e-source-authentication.h
index 122b63e..267f1b0 100644
--- a/libedataserver/e-source-authentication.h
+++ b/libedataserver/e-source-authentication.h
@@ -121,6 +121,13 @@ gchar *            e_source_authentication_dup_user
 void           e_source_authentication_set_user
                                        (ESourceAuthentication *extension,
                                         const gchar *user);
+const gchar *  e_source_authentication_get_credential_name
+                                       (ESourceAuthentication *extension);
+gchar *                e_source_authentication_dup_credential_name
+                                       (ESourceAuthentication *extension);
+void           e_source_authentication_set_credential_name
+                                       (ESourceAuthentication *extension,
+                                        const gchar *credential_name);
 
 G_END_DECLS
 
diff --git a/libedataserver/e-source-credentials-provider-impl-password.c 
b/libedataserver/e-source-credentials-provider-impl-password.c
new file mode 100644
index 0000000..25315bf
--- /dev/null
+++ b/libedataserver/e-source-credentials-provider-impl-password.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-source-credentials-provider-impl-password.h"
+
+struct _ESourceCredentialsProviderImplPasswordPrivate {
+       gboolean dummy;
+};
+
+G_DEFINE_TYPE (ESourceCredentialsProviderImplPassword, e_source_credentials_provider_impl_password, 
E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL)
+
+static gboolean
+e_source_credentials_provider_impl_password_can_process (ESourceCredentialsProviderImpl *provider_impl,
+                                                        ESource *source)
+{
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       /* It can process any source by default */
+       return TRUE;
+}
+
+static gboolean
+e_source_credentials_provider_impl_password_can_store (ESourceCredentialsProviderImpl *provider_impl)
+{
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD (provider_impl), FALSE);
+
+       return TRUE;
+}
+
+static gboolean
+e_source_credentials_provider_impl_password_can_prompt (ESourceCredentialsProviderImpl *provider_impl)
+{
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD (provider_impl), FALSE);
+
+       return TRUE;
+}
+
+static gboolean
+e_source_credentials_provider_impl_password_lookup_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                                        ESource *source,
+                                                        GCancellable *cancellable,
+                                                        ENamedParameters **out_credentials,
+                                                        GError **error)
+{
+       gchar *password = NULL;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (out_credentials != NULL, FALSE);
+
+       *out_credentials = NULL;
+
+       if (!e_source_lookup_password_sync (source, cancellable, &password, error))
+               return FALSE;
+
+       if (!password) {
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, _("Password not found"));
+               return FALSE;
+       }
+
+       *out_credentials = e_named_parameters_new ();
+       e_named_parameters_set (*out_credentials, E_SOURCE_CREDENTIAL_PASSWORD, password);
+
+       e_util_safe_free_string (password);
+
+       return TRUE;
+}
+
+static gboolean
+e_source_credentials_provider_impl_password_store_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                                       ESource *source,
+                                                       const ENamedParameters *credentials,
+                                                       gboolean permanently,
+                                                       GCancellable *cancellable,
+                                                       GError **error)
+{
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (credentials != NULL, FALSE);
+       g_return_val_if_fail (e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_PASSWORD) != NULL, 
FALSE);
+
+       return e_source_store_password_sync (source,
+               e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_PASSWORD),
+               permanently, cancellable, error);
+}
+
+static gboolean
+e_source_credentials_provider_impl_password_delete_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                                        ESource *source,
+                                                        GCancellable *cancellable,
+                                                        GError **error)
+{
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       return e_source_delete_password_sync (source, cancellable, error);
+}
+
+static void
+e_source_credentials_provider_impl_password_class_init (ESourceCredentialsProviderImplPasswordClass *klass)
+{
+       ESourceCredentialsProviderImplClass *impl_class;
+
+       g_type_class_add_private (klass, sizeof (ESourceCredentialsProviderImplPasswordPrivate));
+
+       impl_class = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_CLASS (klass);
+       impl_class->can_process = e_source_credentials_provider_impl_password_can_process;
+       impl_class->can_store = e_source_credentials_provider_impl_password_can_store;
+       impl_class->can_prompt = e_source_credentials_provider_impl_password_can_prompt;
+       impl_class->lookup_sync = e_source_credentials_provider_impl_password_lookup_sync;
+       impl_class->store_sync = e_source_credentials_provider_impl_password_store_sync;
+       impl_class->delete_sync = e_source_credentials_provider_impl_password_delete_sync;
+}
+
+static void
+e_source_credentials_provider_impl_password_init (ESourceCredentialsProviderImplPassword *provider_impl)
+{
+       provider_impl->priv = G_TYPE_INSTANCE_GET_PRIVATE (provider_impl,
+               E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD, 
ESourceCredentialsProviderImplPasswordPrivate);
+}
diff --git a/libedataserver/e-source-credentials-provider-impl-password.h 
b/libedataserver/e-source-credentials-provider-impl-password.h
new file mode 100644
index 0000000..64343e3
--- /dev/null
+++ b/libedataserver/e-source-credentials-provider-impl-password.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
+#error "Only <libedataserver/libedataserver.h> should be included directly."
+#endif
+
+#ifndef E_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD_H
+#define E_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libedataserver/e-source-credentials-provider-impl.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD \
+       (e_source_credentials_provider_impl_password_get_type ())
+#define E_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD, ESourceCredentialsProviderImplPassword))
+#define E_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD, 
ESourceCredentialsProviderImplPasswordClass))
+#define E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD))
+#define E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD))
+#define E_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD, 
ESourceCredentialsProviderImplPasswordClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceCredentialsProviderImplPassword ESourceCredentialsProviderImplPassword;
+typedef struct _ESourceCredentialsProviderImplPasswordClass ESourceCredentialsProviderImplPasswordClass;
+typedef struct _ESourceCredentialsProviderImplPasswordPrivate ESourceCredentialsProviderImplPasswordPrivate;
+
+/**
+ * ESourceCredentialsProviderImplPassword:
+ *
+ * Password based credentials provider implementation.
+ *
+ * Since: 3.14
+ **/
+struct _ESourceCredentialsProviderImplPassword {
+       ESourceCredentialsProviderImpl parent;
+       ESourceCredentialsProviderImplPasswordPrivate *priv;
+};
+
+struct _ESourceCredentialsProviderImplPasswordClass {
+       ESourceCredentialsProviderImplClass parent_class;
+};
+
+GType          e_source_credentials_provider_impl_password_get_type    (void);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD_H */
diff --git a/libedataserver/e-source-credentials-provider-impl.c 
b/libedataserver/e-source-credentials-provider-impl.c
new file mode 100644
index 0000000..1082208
--- /dev/null
+++ b/libedataserver/e-source-credentials-provider-impl.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include "e-source-credentials-provider.h"
+#include "e-source-credentials-provider-impl.h"
+
+struct _ESourceCredentialsProviderImplPrivate {
+       gboolean dummy;
+};
+
+G_DEFINE_ABSTRACT_TYPE (ESourceCredentialsProviderImpl, e_source_credentials_provider_impl, E_TYPE_EXTENSION)
+
+static gboolean
+source_credentials_provider_impl_lookup_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                             ESource *source,
+                                             GCancellable *cancellable,
+                                             ENamedParameters **out_credentials,
+                                             GError **error)
+{
+       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Credentials lookup is not 
supported"));
+
+       return FALSE;
+}
+
+static gboolean
+source_credentials_provider_impl_store_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                            ESource *source,
+                                            const ENamedParameters *credentials,
+                                            gboolean permanently,
+                                            GCancellable *cancellable,
+                                            GError **error)
+{
+       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Credentials store is not 
supported"));
+
+       return FALSE;
+}
+
+static gboolean
+source_credentials_provider_impl_delete_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                             ESource *source,
+                                             GCancellable *cancellable,
+                                             GError **error)
+{
+       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Credentials delete is not 
supported"));
+
+       return FALSE;
+}
+
+static void
+e_source_credentials_provider_impl_constructed (GObject *object)
+{
+       ESourceCredentialsProviderImpl *provider_impl = E_SOURCE_CREDENTIALS_PROVIDER_IMPL (object);
+       ESourceCredentialsProvider *provider;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_source_credentials_provider_impl_parent_class)->constructed (object);
+
+       provider = E_SOURCE_CREDENTIALS_PROVIDER (e_extension_get_extensible (E_EXTENSION (provider_impl)));
+
+       e_source_credentials_provider_register_impl (provider, provider_impl);
+}
+
+static void
+e_source_credentials_provider_impl_class_init (ESourceCredentialsProviderImplClass *klass)
+{
+       GObjectClass *object_class;
+       EExtensionClass *extension_class;
+       ESourceCredentialsProviderImplClass *provider_impl_class;
+
+       g_type_class_add_private (klass, sizeof (ESourceCredentialsProviderImplPrivate));
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->constructed = e_source_credentials_provider_impl_constructed;
+
+       extension_class = E_EXTENSION_CLASS (klass);
+       extension_class->extensible_type = E_TYPE_SOURCE_CREDENTIALS_PROVIDER;
+
+       provider_impl_class = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_CLASS (klass);
+       provider_impl_class->lookup_sync = source_credentials_provider_impl_lookup_sync;
+       provider_impl_class->store_sync = source_credentials_provider_impl_store_sync;
+       provider_impl_class->delete_sync = source_credentials_provider_impl_delete_sync;
+}
+
+static void
+e_source_credentials_provider_impl_init (ESourceCredentialsProviderImpl *provider_impl)
+{
+       provider_impl->priv = G_TYPE_INSTANCE_GET_PRIVATE (provider_impl,
+               E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL, ESourceCredentialsProviderImplPrivate);
+}
+
+/**
+ * e_source_credentials_provider_impl_get_provider:
+ * @provider_impl: an #ESourceCredentialsProviderImpl
+ *
+ * Returns an #ESourceCredentialsProvider with which the @provider_impl is associated.
+ *
+ * Returns: an #ESourceCredentialsProvider
+ *
+ * Since: 3.14
+ **/
+ESourceCredentialsProvider *
+e_source_credentials_provider_impl_get_provider (ESourceCredentialsProviderImpl *provider_impl)
+{
+       EExtensible *extensible;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL (provider_impl), NULL);
+
+       extensible = e_extension_get_extensible (E_EXTENSION (provider_impl));
+       if (!extensible)
+               return NULL;
+
+       return E_SOURCE_CREDENTIALS_PROVIDER (extensible);
+}
+
+/**
+ * e_source_credentials_provider_impl_can_process:
+ * @provider_impl: an #ESourceCredentialsProviderImpl
+ * @source: an #ESource
+ *
+ * Returns whether the @provider_impl can process credentials for the @source.
+ *
+ * Returns: Whether the @provider_impl can process credentials for the @source.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_impl_can_process (ESourceCredentialsProviderImpl *provider_impl,
+                                               ESource *source)
+{
+       ESourceCredentialsProviderImplClass *klass;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       klass = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_GET_CLASS (provider_impl);
+       g_return_val_if_fail (klass->can_process != NULL, FALSE);
+
+       return klass->can_process (provider_impl, source);
+}
+
+/**
+ * e_source_credentials_provider_impl_can_store:
+ * @provider_impl: an #ESourceCredentialsProviderImpl
+ *
+ * Returns whether the @provider_impl can store credentials.
+ *
+ * Returns: Whether the @provider_impl can store credentials.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_impl_can_store (ESourceCredentialsProviderImpl *provider_impl)
+{
+       ESourceCredentialsProviderImplClass *klass;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL (provider_impl), FALSE);
+
+       klass = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_GET_CLASS (provider_impl);
+       g_return_val_if_fail (klass->can_store != NULL, FALSE);
+
+       return klass->can_store (provider_impl);
+}
+
+/**
+ * e_source_credentials_provider_impl_can_prompt:
+ * @provider_impl: an #ESourceCredentialsProviderImpl
+ *
+ * Returns whether credential prompt can be done for the @provider_impl.
+ *
+ * Returns: Whether credential prompt can be done for the @provider_impl.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_impl_can_prompt (ESourceCredentialsProviderImpl *provider_impl)
+{
+       ESourceCredentialsProviderImplClass *klass;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL (provider_impl), FALSE);
+
+       klass = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_GET_CLASS (provider_impl);
+       g_return_val_if_fail (klass->can_prompt != NULL, FALSE);
+
+       return klass->can_prompt (provider_impl);
+}
+
+/**
+ * e_source_credentials_provider_impl_lookup_sync:
+ * @provider_impl: an #ESourceCredentialsProviderImpl
+ * @source: an #ESource
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @out_credentials: an #ENamedParameters to be set with stored credentials
+ * @error: (allow none): return location for a #GError, or %NULL
+ *
+ * Asks @provider_impl to lookup for stored credentials for @source.
+ * The @out_credentials is populated with them. If the result is not
+ * %NULL, then it should be freed with e_anmed_parameters_free() when
+ * no longer needed.
+ *
+ * Default implementation returns %FALSE and sets #G_IO_ERROR_NOT_SUPPORTED error.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_impl_lookup_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                               ESource *source,
+                                               GCancellable *cancellable,
+                                               ENamedParameters **out_credentials,
+                                               GError **error)
+{
+       ESourceCredentialsProviderImplClass *klass;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (out_credentials != NULL, FALSE);
+
+       klass = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_GET_CLASS (provider_impl);
+       g_return_val_if_fail (klass->lookup_sync != NULL, FALSE);
+
+       return klass->lookup_sync (provider_impl, source, cancellable, out_credentials, error);
+}
+
+/**
+ * e_source_credentials_provider_impl_store_sync:
+ * @provider_impl: an #ESourceCredentialsProviderImpl
+ * @source: an #ESource
+ * @credentials: an #ENamedParameters containing credentials to store
+ * @permanently: whether to store credentials permanently, or for the current session only
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @error: (allow none): return location for a #GError, or %NULL
+ *
+ * Asks @provider_impl to store @credentials for @source.
+ *
+ * Default implementation returns %FALSE and sets #G_IO_ERROR_NOT_SUPPORTED error.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_impl_store_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                              ESource *source,
+                                              const ENamedParameters *credentials,
+                                              gboolean permanently,
+                                              GCancellable *cancellable,
+                                              GError **error)
+{
+       ESourceCredentialsProviderImplClass *klass;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (credentials != NULL, FALSE);
+
+       klass = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_GET_CLASS (provider_impl);
+       g_return_val_if_fail (klass->store_sync != NULL, FALSE);
+
+       return klass->store_sync (provider_impl, source, credentials, permanently, cancellable, error);
+}
+
+/**
+ * e_source_credentials_provider_impl_delete_sync:
+ * @provider_impl: an #ESourceCredentialsProviderImpl
+ * @source: an #ESource
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @error: (allow none): return location for a #GError, or %NULL
+ *
+ * Asks @provider_impl to delete any stored credentials for @source.
+ *
+ * Default implementation returns %FALSE and sets #G_IO_ERROR_NOT_SUPPORTED error.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_impl_delete_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                               ESource *source,
+                                               GCancellable *cancellable,
+                                               GError **error)
+{
+       ESourceCredentialsProviderImplClass *klass;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       klass = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_GET_CLASS (provider_impl);
+       g_return_val_if_fail (klass->delete_sync != NULL, FALSE);
+
+       return klass->delete_sync (provider_impl, source, cancellable, error);
+}
diff --git a/libedataserver/e-source-credentials-provider-impl.h 
b/libedataserver/e-source-credentials-provider-impl.h
new file mode 100644
index 0000000..73c5e5e
--- /dev/null
+++ b/libedataserver/e-source-credentials-provider-impl.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
+#error "Only <libedataserver/libedataserver.h> should be included directly."
+#endif
+
+#ifndef E_SOURCE_CREDENTIALS_PROVIDER_IMPL_H
+#define E_SOURCE_CREDENTIALS_PROVIDER_IMPL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libedataserver/e-extension.h>
+#include <libedataserver/e-source.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL \
+       (e_source_credentials_provider_impl_get_type ())
+#define E_SOURCE_CREDENTIALS_PROVIDER_IMPL(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL, ESourceCredentialsProviderImpl))
+#define E_SOURCE_CREDENTIALS_PROVIDER_IMPL_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL, ESourceCredentialsProviderImplClass))
+#define E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL))
+#define E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL))
+#define E_SOURCE_CREDENTIALS_PROVIDER_IMPL_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL, ESourceCredentialsProviderImplClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceCredentialsProviderImpl ESourceCredentialsProviderImpl;
+typedef struct _ESourceCredentialsProviderImplClass ESourceCredentialsProviderImplClass;
+typedef struct _ESourceCredentialsProviderImplPrivate ESourceCredentialsProviderImplPrivate;
+
+struct _ESourceCredentialsProvider;
+
+/**
+ * ESourceCredentialsProviderImpl:
+ *
+ * Credentials provider implementation base structure. The descendants
+ * implement the virtual methods. The descendants are automatically
+ * registered into an #ESourceCredentialsProvider.
+ *
+ * Since: 3.14
+ **/
+struct _ESourceCredentialsProviderImpl {
+       EExtension parent;
+       ESourceCredentialsProviderImplPrivate *priv;
+};
+
+struct _ESourceCredentialsProviderImplClass {
+       EExtensionClass parent_class;
+
+       gboolean        (*can_process)          (ESourceCredentialsProviderImpl *provider_impl,
+                                                ESource *source);
+       gboolean        (*can_store)            (ESourceCredentialsProviderImpl *provider_impl);
+       gboolean        (*can_prompt)           (ESourceCredentialsProviderImpl *provider_impl);
+       gboolean        (*lookup_sync)          (ESourceCredentialsProviderImpl *provider_impl,
+                                                ESource *source,
+                                                GCancellable *cancellable,
+                                                ENamedParameters **out_credentials,
+                                                GError **error);
+       gboolean        (*store_sync)           (ESourceCredentialsProviderImpl *provider_impl,
+                                                ESource *source,
+                                                const ENamedParameters *credentials,
+                                                gboolean permanently,
+                                                GCancellable *cancellable,
+                                                GError **error);
+       gboolean        (*delete_sync)          (ESourceCredentialsProviderImpl *provider_impl,
+                                                ESource *source,
+                                                GCancellable *cancellable,
+                                                GError **error);
+};
+
+GType          e_source_credentials_provider_impl_get_type     (void);
+struct _ESourceCredentialsProvider *
+               e_source_credentials_provider_impl_get_provider
+                                                       (ESourceCredentialsProviderImpl *provider_impl);
+gboolean       e_source_credentials_provider_impl_can_process
+                                                       (ESourceCredentialsProviderImpl *provider_impl,
+                                                        ESource *source);
+gboolean       e_source_credentials_provider_impl_can_store
+                                                       (ESourceCredentialsProviderImpl *provider_impl);
+gboolean       e_source_credentials_provider_impl_can_prompt
+                                                       (ESourceCredentialsProviderImpl *provider_impl);
+gboolean       e_source_credentials_provider_impl_lookup_sync
+                                                       (ESourceCredentialsProviderImpl *provider_impl,
+                                                        ESource *source,
+                                                        GCancellable *cancellable,
+                                                        ENamedParameters **out_credentials,
+                                                        GError **error);
+gboolean       e_source_credentials_provider_impl_store_sync
+                                                       (ESourceCredentialsProviderImpl *provider_impl,
+                                                        ESource *source,
+                                                        const ENamedParameters *credentials,
+                                                        gboolean permanently,
+                                                        GCancellable *cancellable,
+                                                        GError **error);
+gboolean       e_source_credentials_provider_impl_delete_sync
+                                                       (ESourceCredentialsProviderImpl *provider_impl,
+                                                        ESource *source,
+                                                        GCancellable *cancellable,
+                                                        GError **error);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_CREDENTIALS_PROVIDER_IMPL_H */
diff --git a/libedataserver/e-source-credentials-provider.c b/libedataserver/e-source-credentials-provider.c
new file mode 100644
index 0000000..d9b2271
--- /dev/null
+++ b/libedataserver/e-source-credentials-provider.c
@@ -0,0 +1,1030 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+#include "e-data-server-util.h"
+#include "e-source.h"
+#include "e-source-authentication.h"
+#include "e-source-collection.h"
+#include "e-source-registry.h"
+#include "e-source-credentials-provider-impl.h"
+#include "e-module.h"
+
+#include "libedataserver-private.h"
+
+#include "e-source-credentials-provider.h"
+
+/* built-in source credentials provider implementations */
+#include "e-source-credentials-provider-impl-password.h"
+
+struct _ESourceCredentialsProviderPrivate {
+       GWeakRef registry; /* The property can hold both client and server-side registry */
+       GMutex providers_lock;
+       GSList *providers; /* ESourceCredentialsProviderImpl *impl */
+       ESourceCredentialsProviderImpl *impl_password;
+};
+
+enum {
+       PROP_0,
+       PROP_REGISTRY
+};
+
+G_DEFINE_TYPE_WITH_CODE (ESourceCredentialsProvider, e_source_credentials_provider, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
+
+static ESource *
+source_credentials_provider_ref_source (ESourceCredentialsProvider *provider,
+                                       const gchar *uid)
+{
+       GObject *registry;
+       ESource *source = NULL;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), NULL);
+       g_return_val_if_fail (uid, NULL);
+
+       registry = e_source_credentials_provider_ref_registry (provider);
+       if (registry) {
+               g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+               source = e_source_registry_ref_source (E_SOURCE_REGISTRY (registry), uid);
+       }
+
+       g_clear_object (&registry);
+
+       return source;
+}
+
+static void
+source_credentials_provider_set_registry (ESourceCredentialsProvider *provider,
+                                         GObject *registry)
+{
+       g_return_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider));
+       g_return_if_fail (G_IS_OBJECT (registry));
+       g_return_if_fail (g_weak_ref_get (&provider->priv->registry) == NULL);
+
+       g_weak_ref_set (&provider->priv->registry, registry);
+}
+
+static void
+source_credentials_provider_set_property (GObject *object,
+                                         guint property_id,
+                                         const GValue *value,
+                                         GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_REGISTRY:
+                       source_credentials_provider_set_registry (
+                               E_SOURCE_CREDENTIALS_PROVIDER (object),
+                               g_value_get_object (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_credentials_provider_get_property (GObject *object,
+                                         guint property_id,
+                                         GValue *value,
+                                         GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_REGISTRY:
+                       g_value_take_object (value,
+                               e_source_credentials_provider_ref_registry (
+                               E_SOURCE_CREDENTIALS_PROVIDER (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+source_credentials_provider_constructed (GObject *object)
+{
+       ESourceCredentialsProvider *provider = E_SOURCE_CREDENTIALS_PROVIDER (object);
+       GList *module_types;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_source_credentials_provider_parent_class)->constructed (object);
+
+       module_types = e_module_load_all_in_directory (E_DATA_SERVER_CREDENTIALMODULEDIR);
+       g_list_free_full (module_types, (GDestroyNotify) g_type_module_unuse);
+
+       e_extensible_load_extensions (E_EXTENSIBLE (object));
+
+       g_mutex_lock (&provider->priv->providers_lock);
+
+       /* Safety check. */
+       g_warn_if_fail (provider->priv->impl_password != NULL);
+
+       g_mutex_unlock (&provider->priv->providers_lock);
+}
+
+static void
+source_credentials_provider_finalize (GObject *object)
+{
+       ESourceCredentialsProvider *provider = E_SOURCE_CREDENTIALS_PROVIDER (object);
+
+       g_mutex_lock (&provider->priv->providers_lock);
+       g_slist_free_full (provider->priv->providers, g_object_unref);
+       provider->priv->providers = NULL;
+       g_clear_object (&provider->priv->impl_password);
+       g_mutex_unlock (&provider->priv->providers_lock);
+
+       g_mutex_clear (&provider->priv->providers_lock);
+       g_weak_ref_clear (&provider->priv->registry);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_source_credentials_provider_parent_class)->finalize (object);
+}
+
+static void
+e_source_credentials_provider_class_init (ESourceCredentialsProviderClass *class)
+{
+       GObjectClass *object_class;
+       ESourceCredentialsProviderClass *provider_class;
+
+       g_type_class_add_private (class, sizeof (ESourceCredentialsProviderPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = source_credentials_provider_set_property;
+       object_class->get_property = source_credentials_provider_get_property;
+       object_class->constructed = source_credentials_provider_constructed;
+       object_class->finalize = source_credentials_provider_finalize;
+
+       provider_class = E_SOURCE_CREDENTIALS_PROVIDER_CLASS (class);
+       provider_class->ref_source = source_credentials_provider_ref_source;
+
+       /**
+        * ESourceCredentialsProvider:registry:
+        *
+        * The Source Registry object, which can be either #ESourceregistry or #ESourceRegistryServer.
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_REGISTRY,
+               g_param_spec_object (
+                       "registry",
+                       "Registry",
+                       "An ESourceRegistry",
+                       G_TYPE_OBJECT,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       /* Ensure built-in credential providers implementation types */
+       g_type_ensure (E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD);
+}
+
+static void
+e_source_credentials_provider_init (ESourceCredentialsProvider *provider)
+{
+       provider->priv = G_TYPE_INSTANCE_GET_PRIVATE (provider, E_TYPE_SOURCE_CREDENTIALS_PROVIDER, 
ESourceCredentialsProviderPrivate);
+
+       g_weak_ref_init (&provider->priv->registry, NULL);
+       provider->priv->providers = NULL;
+       g_mutex_init (&provider->priv->providers_lock);
+}
+
+static ESourceCredentialsProviderImpl *
+source_credential_provider_ref_impl_for_source (ESourceCredentialsProvider *provider,
+                                               ESource *source,
+                                               ESource **out_cred_source)
+{
+       ESourceCredentialsProviderImpl *impl = NULL;
+       ESource *cred_source;
+       GSList *link;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), NULL);
+       g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+       if (out_cred_source)
+               *out_cred_source = NULL;
+
+       cred_source = e_source_credentials_provider_ref_credentials_source (provider, source);
+       if (!cred_source || cred_source == source) {
+               g_clear_object (&cred_source);
+       } else {
+               source = cred_source;
+               if (out_cred_source)
+                       *out_cred_source = g_object_ref (cred_source);
+       }
+
+       g_mutex_lock (&provider->priv->providers_lock);
+
+       for (link = provider->priv->providers; link; link = link->next) {
+               ESourceCredentialsProviderImpl *adept = link->data;
+
+               if (adept && e_source_credentials_provider_impl_can_process (adept, source)) {
+                       impl = g_object_ref (adept);
+                       break;
+               }
+       }
+
+       if (!impl && provider->priv->impl_password)
+               impl = g_object_ref (provider->priv->impl_password);
+
+       g_mutex_unlock (&provider->priv->providers_lock);
+
+       g_clear_object (&cred_source);
+
+       if (!impl && out_cred_source)
+               g_clear_object (out_cred_source);
+
+       return impl;
+}
+
+/**
+ * e_source_credentials_provider_new:
+ * @registry: an #ESourceRegistry
+ *
+ * Creates a new #ESourceCredentialsProvider, which is meant to abstract
+ * credential management for #ESource<!-- -->-s.
+ *
+ * Returns: (transfer full): a new #ESourceCredentialsProvider
+ *
+ * Since: 3.14
+ **/
+ESourceCredentialsProvider *
+e_source_credentials_provider_new (ESourceRegistry *registry)
+{
+       g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), NULL);
+
+       return g_object_new (E_TYPE_SOURCE_CREDENTIALS_PROVIDER,
+               "registry", registry,
+               NULL);
+}
+
+/**
+ * e_source_credentials_provider_ref_registry:
+ * @provider: an #ESourceCredentialsProvider
+ *
+ * Returns refenrenced registry associated with this @provider.
+ *
+ * Returns: Reference registry associated with this @provider. Unref it
+ *    with g_object_unref() when no longer needed.
+ *
+ * Since: 3.14
+ **/
+GObject *
+e_source_credentials_provider_ref_registry (ESourceCredentialsProvider *provider)
+{
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), NULL);
+
+       return g_weak_ref_get (&provider->priv->registry);
+}
+
+/**
+ * e_source_credentials_provider_register_impl:
+ * @provider: an #ESourceCredentialsProvider
+ * @provider_impl: an #ESourceCredentialsProviderImpl
+ *
+ * Registers a credentials provider implementation and adds its own reference on
+ * the @provider_impl.
+ *
+ * Returns: %TRUE on success, %FALSE on failure, like when there is
+ *    the @provider_impl already registered.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_register_impl (ESourceCredentialsProvider *provider,
+                                            ESourceCredentialsProviderImpl *provider_impl)
+{
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL (provider_impl), FALSE);
+
+       g_mutex_lock (&provider->priv->providers_lock);
+       if (g_slist_find (provider->priv->providers, provider_impl)) {
+               g_mutex_unlock (&provider->priv->providers_lock);
+               return FALSE;
+       }
+
+       /* Deal with the built-in password provider differently, it's a fallback provider_impl */
+       if (E_IS_SOURCE_CREDENTIALS_PROVIDER_IMPL_PASSWORD (provider_impl)) {
+               if (provider_impl == provider->priv->impl_password) {
+                       g_mutex_unlock (&provider->priv->providers_lock);
+                       return FALSE;
+               }
+
+               g_clear_object (&provider->priv->impl_password);
+               provider->priv->impl_password = g_object_ref (provider_impl);
+       } else {
+               provider->priv->providers = g_slist_prepend (provider->priv->providers, g_object_ref 
(provider_impl));
+       }
+
+       g_mutex_unlock (&provider->priv->providers_lock);
+
+       return TRUE;
+}
+
+/**
+ * e_source_credentials_provider_unregister_impl:
+ * @provider: an #ESourceCredentialsProvider
+ * @provider_impl: an #ESourceCredentialsProviderImpl
+ *
+ * Unregisters previously registered @provider_impl with
+ * e_source_credentials_provider_register_impl(). Function does nothing,
+ * when the @provider_impl is not registered.
+ *
+ * Since: 3.14
+ **/
+void
+e_source_credentials_provider_unregister_impl (ESourceCredentialsProvider *provider,
+                                              ESourceCredentialsProviderImpl *provider_impl)
+{
+       g_return_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider));
+
+       g_mutex_lock (&provider->priv->providers_lock);
+
+       provider->priv->providers = g_slist_remove (provider->priv->providers, provider_impl);
+
+       g_mutex_unlock (&provider->priv->providers_lock);
+}
+
+/**
+ * e_source_credentials_provider_ref_source:
+ * @provider: an #ESourceCredentialsProvider
+ * @uid: an #ESource UID
+ *
+ * Returns referenced #ESource with the given @uid, or %NULL, when it could not be found.
+ *
+ * Returns: (transfer full): Referenced #ESource with the given @uid, or %NULL, when it
+ *    could not be found. Unref the returned #ESource with g_object_unref(), when no longer needed.
+ *
+ * Since: 3.14
+ **/
+ESource *
+e_source_credentials_provider_ref_source (ESourceCredentialsProvider *provider,
+                                         const gchar *uid)
+{
+       ESourceCredentialsProviderClass *klass;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), NULL);
+       g_return_val_if_fail (uid != NULL, NULL);
+
+       klass = E_SOURCE_CREDENTIALS_PROVIDER_GET_CLASS (provider);
+       g_return_val_if_fail (klass->ref_source != NULL, NULL);
+
+       return klass->ref_source (provider, uid);
+}
+
+/**
+ * e_source_credentials_provider_ref_credentials_source:
+ * @provider: an #ESourceCredentialsProvider
+ * @source: an #ESource
+ *
+ * Returns a referenced parent #ESource, which holds the credentials for
+ * the given @source. This is useful for collections, where the credentials
+ * are usually stored on the collection source, thus shared between child
+ * sources. When ther eis no such parent source, a %NULL is returned, which
+ * means the @source holds credentials for itself.
+ *
+ * Returns: referenced parent #ESource, which holds credentials, or %NULL. Unref
+ *    the returned non-NULL #ESource with g_object_unref(), when no longer needed.
+ *
+ * Since: 3.14
+ **/
+ESource *
+e_source_credentials_provider_ref_credentials_source (ESourceCredentialsProvider *provider,
+                                                     ESource *source)
+{
+       ESource *collection, *cred_source = NULL;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), NULL);
+       g_return_val_if_fail (E_IS_SOURCE (source), NULL);
+
+       collection = g_object_ref (source);
+
+       while (collection &&
+              !e_source_has_extension (collection, E_SOURCE_EXTENSION_COLLECTION)) {
+               ESource *parent;
+
+               if (!e_source_get_parent (collection)) {
+                       break;
+               }
+
+               parent = e_source_credentials_provider_ref_source (provider, e_source_get_parent 
(collection));
+
+               g_clear_object (&collection);
+               collection = parent;
+       }
+
+       if (collection && e_source_has_extension (collection, E_SOURCE_EXTENSION_COLLECTION)) {
+               gboolean can_use_collection = FALSE;
+
+               /* Use the found parent collection source for credentials store only if
+                  the child source doesn't have any authentication information, or this
+                  information is not filled, or if either the host name or the user name
+                  are the same with the collection source.
+
+                  This allows to create a collection of sources which has one source
+                  (like message send) on a different server, thus this source uses
+                  its own credentials.
+               */
+               if (!e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
+                       can_use_collection = TRUE;
+               } else if (e_source_has_extension (collection, E_SOURCE_EXTENSION_AUTHENTICATION)) {
+                       ESourceAuthentication *auth_source, *auth_collection;
+                       gchar *host_source, *host_collection;
+
+                       auth_source = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
+                       auth_collection = e_source_get_extension (collection, 
E_SOURCE_EXTENSION_AUTHENTICATION);
+
+                       host_source = e_source_authentication_dup_host (auth_source);
+                       host_collection = e_source_authentication_dup_host (auth_collection);
+
+                       if (host_source && host_collection && g_ascii_strcasecmp (host_source, 
host_collection) == 0) {
+                               gchar *username_source, *username_collection;
+
+                               username_source = e_source_authentication_dup_user (auth_source);
+                               username_collection = e_source_authentication_dup_user (auth_collection);
+
+                               if (username_source && username_collection && g_ascii_strcasecmp 
(username_source, username_collection) == 0) {
+                                       can_use_collection = TRUE;
+                               } else {
+                                       can_use_collection = !username_source || !*username_source;
+                               }
+
+                               g_free (username_source);
+                               g_free (username_collection);
+                       } else {
+                               /* Only one of them is filled, then use the collection; otherwise
+                                  both are filled and they do not match, thus do not use collection. */
+                               can_use_collection = (host_collection && *host_collection && (!host_source || 
!*host_source)) ||
+                                                    (host_source && *host_source && (!host_collection || 
!*host_collection));
+                       }
+
+                       g_free (host_source);
+                       g_free (host_collection);
+               }
+
+               if (can_use_collection)
+                       cred_source = g_object_ref (collection);
+       }
+
+       g_clear_object (&collection);
+
+       return cred_source;
+}
+
+/**
+ * e_source_credentials_provider_can_store:
+ * @provider: an #ESourceCredentialsProvider
+ * @source: an #ESource
+ *
+ * Returns whether the @source can store its credentials. When %FALSE is returned,
+ * an attempt to call e_source_credentials_provider_store() or
+ * e_source_credentials_provider_store_sync() will fail for this @source.
+ *
+ * Returns: %TRUE, when the credentials storing for @source is possible, %FALSE otherwise.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_can_store (ESourceCredentialsProvider *provider,
+                                        ESource *source)
+{
+       ESourceCredentialsProviderImpl *provider_impl;
+       gboolean res;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       provider_impl = source_credential_provider_ref_impl_for_source (provider, source, NULL);
+
+       g_return_val_if_fail (provider_impl != NULL, FALSE);
+       res = e_source_credentials_provider_impl_can_store (provider_impl);
+
+       g_clear_object (&provider_impl);
+
+       return res;
+}
+
+/**
+ * e_source_credentials_provider_can_prompt:
+ * @provider: an #ESourceCredentialsProvider
+ * @source: an #ESource
+ *
+ * Returns whether a credentials prompt can be shown for the @source.
+ *
+ * Returns: %TRUE, when a credentials prompt can be shown for @source, %FALSE otherwise.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_can_prompt (ESourceCredentialsProvider *provider,
+                                         ESource *source)
+{
+       ESourceCredentialsProviderImpl *provider_impl;
+       gboolean res;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       provider_impl = source_credential_provider_ref_impl_for_source (provider, source, NULL);
+       g_return_val_if_fail (provider_impl != NULL, FALSE);
+
+       res = e_source_credentials_provider_impl_can_prompt (provider_impl);
+
+       g_clear_object (&provider_impl);
+
+       return res;
+}
+
+typedef struct _AsyncContext {
+       ESource *source;
+       ENamedParameters *credentials;
+       gboolean permanently;
+} AsyncContext;
+
+static AsyncContext *
+async_context_new (ESource *source,
+                  const ENamedParameters *credentials,
+                  gboolean permanently)
+{
+       AsyncContext *async_context;
+
+       async_context = g_new0 (AsyncContext, 1);
+       async_context->source = g_object_ref (source);
+       async_context->permanently = permanently;
+       if (credentials)
+               async_context->credentials = e_named_parameters_new_clone (credentials);
+
+       return async_context;
+}
+
+static void
+async_context_free (gpointer ptr)
+{
+       AsyncContext *async_context = ptr;
+
+       if (async_context) {
+               g_clear_object (&async_context->source);
+               e_named_parameters_free (async_context->credentials);
+               g_free (async_context);
+       }
+}
+
+/**
+ * e_source_credentials_provider_lookup_sync:
+ * @provider: an #ESourceCredentialsProvider
+ * @source: an #ESource, to lookup credentials for
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @out_credentials: (out): return location for the credentials
+ * @error: return location for a #GError, or %NULL
+ *
+ * Looks up the credentials for @source.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_lookup_sync (ESourceCredentialsProvider *provider,
+                                          ESource *source,
+                                          GCancellable *cancellable,
+                                          ENamedParameters **out_credentials,
+                                          GError **error)
+{
+       ESourceCredentialsProviderImpl *provider_impl;
+       ESource *cred_source = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (out_credentials != NULL, FALSE);
+
+       provider_impl = source_credential_provider_ref_impl_for_source (provider, source, &cred_source);
+       g_return_val_if_fail (provider_impl != NULL, FALSE);
+
+       success = e_source_credentials_provider_impl_lookup_sync (provider_impl, cred_source ? cred_source : 
source, cancellable, out_credentials, error);
+
+       g_clear_object (&provider_impl);
+       g_clear_object (&cred_source);
+
+       return success;
+}
+
+static void
+source_credentials_provider_lookup_thread (GTask *task,
+                                          gpointer source_object,
+                                          gpointer task_data,
+                                          GCancellable *cancellable)
+{
+       ESourceCredentialsProvider *provider = source_object;
+       AsyncContext *async_context = task_data;
+       gboolean success;
+       GError *local_error = NULL;
+
+       success = e_source_credentials_provider_lookup_sync (provider,
+               async_context->source,
+               cancellable,
+               &async_context->credentials,
+               &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
+}
+
+/**
+ * e_source_credentials_provider_lookup:
+ * @provider: an #ESourceCredentialsProvider
+ * @source: an #ESource, to lookup credentials for
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously looks up for credentials for @source.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_source_credentials_provider_lookup_finish() to get the result
+ * of the operation.
+ *
+ * Since: 3.14
+ **/
+void
+e_source_credentials_provider_lookup (ESourceCredentialsProvider *provider,
+                                     ESource *source,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+       ESourceCredentialsProviderImpl *provider_impl;
+       ESource *cred_source = NULL;
+       GTask *task;
+       AsyncContext *async_context;
+
+       g_return_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider));
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       provider_impl = source_credential_provider_ref_impl_for_source (provider, source, &cred_source);
+       g_return_if_fail (provider_impl != NULL);
+
+       async_context = async_context_new (cred_source ? cred_source : source, NULL, FALSE);
+
+       task = g_task_new (provider, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_source_credentials_provider_lookup);
+       g_task_set_task_data (task, async_context, async_context_free);
+
+       g_task_run_in_thread (task, source_credentials_provider_lookup_thread);
+
+       g_object_unref (task);
+       g_clear_object (&provider_impl);
+       g_clear_object (&cred_source);
+}
+
+/**
+ * e_source_credentials_provider_lookup_finish:
+ * @provider: an #ESourceCredentialsProvider
+ * @result: a #GAsyncResult
+ * @out_credentials: (out): return location for the credentials
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_credentials_provider_lookup().
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_lookup_finish (ESourceCredentialsProvider *provider,
+                                            GAsyncResult *result,
+                                            ENamedParameters **out_credentials,
+                                            GError **error)
+{
+       AsyncContext *async_context;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), FALSE);
+       g_return_val_if_fail (out_credentials != NULL, FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, provider), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_source_credentials_provider_lookup), FALSE);
+
+       async_context = g_task_get_task_data (G_TASK (result));
+
+       if (!g_task_had_error (G_TASK (result))) {
+               *out_credentials = async_context->credentials;
+               async_context->credentials = NULL;
+       }
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+/**
+ * e_source_credentials_provider_store_sync:
+ * @provider: an #ESourceCredentialsProvider
+ * @source: an #ESource, to store credentials for
+ * @credentials: an #ENamedParameters with credentials to store
+ * @permanently: store permanently or just for the session
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Stores the @credentials for @source. Note the actual stored values
+ * can differ for each storage. In other words, not all named parameters
+ * are stored for each @source.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_store_sync (ESourceCredentialsProvider *provider,
+                                         ESource *source,
+                                         const ENamedParameters *credentials,
+                                         gboolean permanently,
+                                         GCancellable *cancellable,
+                                         GError **error)
+{
+       ESourceCredentialsProviderImpl *provider_impl;
+       ESource *cred_source = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (credentials != NULL, FALSE);
+
+       provider_impl = source_credential_provider_ref_impl_for_source (provider, source, &cred_source);
+       g_return_val_if_fail (provider_impl != NULL, FALSE);
+
+       success = e_source_credentials_provider_impl_store_sync (provider_impl, cred_source ? cred_source : 
source, credentials, permanently, cancellable, error);
+
+       g_clear_object (&provider_impl);
+       g_clear_object (&cred_source);
+
+       return success;
+}
+
+static void
+source_credentials_provider_store_thread (GTask *task,
+                                         gpointer source_object,
+                                         gpointer task_data,
+                                         GCancellable *cancellable)
+{
+       ESourceCredentialsProvider *provider = source_object;
+       AsyncContext *async_context = task_data;
+       gboolean success;
+       GError *local_error = NULL;
+
+       success = e_source_credentials_provider_store_sync (provider,
+               async_context->source,
+               async_context->credentials,
+               async_context->permanently,
+               cancellable,
+               &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
+}
+
+/**
+ * e_source_credentials_provider_store:
+ * @provider: an #ESourceCredentialsProvider
+ * @source: an #ESource, to lookup credentials for
+ * @credentials: an #ENamedParameters with credentials to store
+ * @permanently: store permanently or just for the session
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously stores the @credentials for @source. Note the actual stored
+ * values can differ for each storage. In other words, not all named parameters
+ * are stored for each @source.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_source_credentials_provider_store_finish() to get the result
+ * of the operation.
+ *
+ * Since: 3.14
+ **/
+void
+e_source_credentials_provider_store (ESourceCredentialsProvider *provider,
+                                    ESource *source,
+                                    const ENamedParameters *credentials,
+                                    gboolean permanently,
+                                    GCancellable *cancellable,
+                                    GAsyncReadyCallback callback,
+                                    gpointer user_data)
+{
+       ESourceCredentialsProviderImpl *provider_impl;
+       ESource *cred_source = NULL;
+       GTask *task;
+       AsyncContext *async_context;
+
+       g_return_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider));
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       provider_impl = source_credential_provider_ref_impl_for_source (provider, source, &cred_source);
+       g_return_if_fail (provider_impl != NULL);
+
+       async_context = async_context_new (cred_source ? cred_source : source, credentials, permanently);
+
+       task = g_task_new (provider, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_source_credentials_provider_store);
+       g_task_set_task_data (task, async_context, async_context_free);
+
+       g_task_run_in_thread (task, source_credentials_provider_store_thread);
+
+       g_object_unref (task);
+       g_clear_object (&provider_impl);
+       g_clear_object (&cred_source);
+}
+
+/**
+ * e_source_credentials_provider_store_finish:
+ * @provider: an #ESourceCredentialsProvider
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_credentials_provider_store().
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_store_finish (ESourceCredentialsProvider *provider,
+                                           GAsyncResult *result,
+                                           GError **error)
+{
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, provider), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_source_credentials_provider_store), FALSE);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+/**
+ * e_source_credentials_provider_delete_sync:
+ * @provider: an #ESourceCredentialsProvider
+ * @source: an #ESource, to store credentials for
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @error: return location for a #GError, or %NULL
+ *
+ * Deletes any previously stored credentials for @source.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_delete_sync (ESourceCredentialsProvider *provider,
+                                          ESource *source,
+                                          GCancellable *cancellable,
+                                          GError **error)
+{
+       ESourceCredentialsProviderImpl *provider_impl;
+       ESource *cred_source = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       provider_impl = source_credential_provider_ref_impl_for_source (provider, source, &cred_source);
+       g_return_val_if_fail (provider_impl != NULL, FALSE);
+
+       success = e_source_credentials_provider_impl_delete_sync (provider_impl, cred_source ? cred_source : 
source, cancellable, error);
+
+       g_clear_object (&provider_impl);
+       g_clear_object (&cred_source);
+
+       return success;
+}
+
+static void
+source_credentials_provider_delete_thread (GTask *task,
+                                          gpointer source_object,
+                                          gpointer task_data,
+                                          GCancellable *cancellable)
+{
+       ESourceCredentialsProvider *provider = source_object;
+       AsyncContext *async_context = task_data;
+       gboolean success;
+       GError *local_error = NULL;
+
+       success = e_source_credentials_provider_delete_sync (provider,
+               async_context->source, cancellable, &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
+}
+
+/**
+ * e_source_credentials_provider_delete:
+ * @provider: an #ESourceCredentialsProvider
+ * @source: an #ESource, to lookup credentials for
+ * @cancellable: optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously deletes any previously stored credentials for @source.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_source_credentials_provider_delete_finish() to get the result
+ * of the operation.
+ *
+ * Since: 3.14
+ **/
+void
+e_source_credentials_provider_delete (ESourceCredentialsProvider *provider,
+                                     ESource *source,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+       ESourceCredentialsProviderImpl *provider_impl;
+       ESource *cred_source = NULL;
+       GTask *task;
+       AsyncContext *async_context;
+
+       g_return_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider));
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       provider_impl = source_credential_provider_ref_impl_for_source (provider, source, &cred_source);
+       g_return_if_fail (provider_impl != NULL);
+
+       async_context = async_context_new (cred_source ? cred_source : source, NULL, FALSE);
+
+       task = g_task_new (provider, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_source_credentials_provider_delete);
+       g_task_set_task_data (task, async_context, async_context_free);
+
+       g_task_run_in_thread (task, source_credentials_provider_delete_thread);
+
+       g_object_unref (task);
+       g_clear_object (&provider_impl);
+       g_clear_object (&cred_source);
+}
+
+/**
+ * e_source_credentials_provider_delete_finish:
+ * @provider: an #ESourceCredentialsProvider
+ * @result: a #GAsyncResult
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_credentials_provider_delete().
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_credentials_provider_delete_finish (ESourceCredentialsProvider *provider,
+                                            GAsyncResult *result,
+                                            GError **error)
+{
+       g_return_val_if_fail (E_IS_SOURCE_CREDENTIALS_PROVIDER (provider), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, provider), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_source_credentials_provider_delete), FALSE);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
diff --git a/libedataserver/e-source-credentials-provider.h b/libedataserver/e-source-credentials-provider.h
new file mode 100644
index 0000000..337a55a
--- /dev/null
+++ b/libedataserver/e-source-credentials-provider.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined (__LIBEDATASERVER_H_INSIDE__) && !defined (LIBEDATASERVER_COMPILATION)
+#error "Only <libedataserver/libedataserver.h> should be included directly."
+#endif
+
+#ifndef E_SOURCE_CREDENTIALS_PROVIDER_H
+#define E_SOURCE_CREDENTIALS_PROVIDER_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-source.h>
+#include <libedataserver/e-source-registry.h>
+#include <libedataserver/e-source-credentials-provider-impl.h>
+
+/* Standard GObject macros */
+#define E_TYPE_SOURCE_CREDENTIALS_PROVIDER \
+       (e_source_credentials_provider_get_type ())
+#define E_SOURCE_CREDENTIALS_PROVIDER(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_SOURCE_CREDENTIALS_PROVIDER, ESourceCredentialsProvider))
+#define E_SOURCE_CREDENTIALS_PROVIDER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_SOURCE_CREDENTIALS_PROVIDER, ESourceCredentialsProviderClass))
+#define E_IS_SOURCE_CREDENTIALS_PROVIDER(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_SOURCE_CREDENTIALS_PROVIDER))
+#define E_IS_SOURCE_CREDENTIALS_PROVIDER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_SOURCE_CREDENTIALS_PROVIDER))
+#define E_SOURCE_CREDENTIALS_PROVIDER_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_SOURCE_CREDENTIALS_PROVIDER, ESourceCredentialsProviderClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ESourceCredentialsProvider ESourceCredentialsProvider;
+typedef struct _ESourceCredentialsProviderClass ESourceCredentialsProviderClass;
+typedef struct _ESourceCredentialsProviderPrivate ESourceCredentialsProviderPrivate;
+
+/**
+ * ESourceCredentialsProvider:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.14
+ **/
+struct _ESourceCredentialsProvider {
+       GObject parent;
+       ESourceCredentialsProviderPrivate *priv;
+};
+
+struct _ESourceCredentialsProviderClass {
+       GObjectClass parent_class;
+
+       ESource *       (*ref_source)   (ESourceCredentialsProvider *provider,
+                                        const gchar *uid);
+};
+
+GType          e_source_credentials_provider_get_type  (void) G_GNUC_CONST;
+ESourceCredentialsProvider *
+               e_source_credentials_provider_new       (ESourceRegistry *registry);
+GObject *      e_source_credentials_provider_ref_registry
+                                                       (ESourceCredentialsProvider *provider);
+gboolean       e_source_credentials_provider_register_impl
+                                                       (ESourceCredentialsProvider *provider,
+                                                        ESourceCredentialsProviderImpl *provider_impl);
+void           e_source_credentials_provider_unregister_impl
+                                                       (ESourceCredentialsProvider *provider,
+                                                        ESourceCredentialsProviderImpl *provider_impl);
+ESource *      e_source_credentials_provider_ref_source
+                                                       (ESourceCredentialsProvider *provider,
+                                                        const gchar *uid);
+ESource *      e_source_credentials_provider_ref_credentials_source
+                                                       (ESourceCredentialsProvider *provider,
+                                                        ESource *source);
+gboolean       e_source_credentials_provider_can_store (ESourceCredentialsProvider *provider,
+                                                        ESource *source);
+gboolean       e_source_credentials_provider_can_prompt(ESourceCredentialsProvider *provider,
+                                                        ESource *source);
+gboolean       e_source_credentials_provider_lookup_sync
+                                                       (ESourceCredentialsProvider *provider,
+                                                        ESource *source,
+                                                        GCancellable *cancellable,
+                                                        ENamedParameters **out_credentials,
+                                                        GError **error);
+void           e_source_credentials_provider_lookup    (ESourceCredentialsProvider *provider,
+                                                        ESource *source,
+                                                        GCancellable *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer user_data);
+gboolean       e_source_credentials_provider_lookup_finish
+                                                       (ESourceCredentialsProvider *provider,
+                                                        GAsyncResult *result,
+                                                        ENamedParameters **out_credentials,
+                                                        GError **error);
+gboolean       e_source_credentials_provider_store_sync(ESourceCredentialsProvider *provider,
+                                                        ESource *source,
+                                                        const ENamedParameters *credentials,
+                                                        gboolean permanently,
+                                                        GCancellable *cancellable,
+                                                        GError **error);
+void           e_source_credentials_provider_store     (ESourceCredentialsProvider *provider,
+                                                        ESource *source,
+                                                        const ENamedParameters *credentials,
+                                                        gboolean permanently,
+                                                        GCancellable *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer user_data);
+gboolean       e_source_credentials_provider_store_finish
+                                                       (ESourceCredentialsProvider *provider,
+                                                        GAsyncResult *result,
+                                                        GError **error);
+gboolean       e_source_credentials_provider_delete_sync
+                                                       (ESourceCredentialsProvider *provider,
+                                                        ESource *source,
+                                                        GCancellable *cancellable,
+                                                        GError **error);
+void           e_source_credentials_provider_delete    (ESourceCredentialsProvider *provider,
+                                                        ESource *source,
+                                                        GCancellable *cancellable,
+                                                        GAsyncReadyCallback callback,
+                                                        gpointer user_data);
+gboolean       e_source_credentials_provider_delete_finish
+                                                       (ESourceCredentialsProvider *provider,
+                                                        GAsyncResult *result,
+                                                        GError **error);
+
+G_END_DECLS
+
+#endif /* E_SOURCE_CREDENTIALS_PROVIDER_H */
diff --git a/libedataserver/e-source-enums.h b/libedataserver/e-source-enums.h
index dec37f0..e33ccc4 100644
--- a/libedataserver/e-source-enums.h
+++ b/libedataserver/e-source-enums.h
@@ -69,19 +69,25 @@ typedef enum {
  * ESourceAuthenticationResult:
  * @E_SOURCE_AUTHENTICATION_ERROR:
  *   An error occurred while authenticating.
+ * @E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED:
+ *   An SSL certificate check failed. Since: 3.14.
  * @E_SOURCE_AUTHENTICATION_ACCEPTED:
  *   Server requesting authentication accepted password.
  * @E_SOURCE_AUTHENTICATION_REJECTED:
  *   Server requesting authentication rejected password.
+ * @E_SOURCE_AUTHENTICATION_REQUIRED:
+ *   Server requesting authentication, but none was given.
  *
- * Status codes used by the #ESourceAuthenticator interface.
+ * Status codes used by the #EBackend authentication wrapper.
  *
  * Since: 3.6
  **/
 typedef enum {
        E_SOURCE_AUTHENTICATION_ERROR,
+       E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED,
        E_SOURCE_AUTHENTICATION_ACCEPTED,
-       E_SOURCE_AUTHENTICATION_REJECTED
+       E_SOURCE_AUTHENTICATION_REJECTED,
+       E_SOURCE_AUTHENTICATION_REQUIRED
 } ESourceAuthenticationResult;
 
 /**
@@ -99,4 +105,66 @@ typedef enum {
        E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY = 3
 } ETrustPromptResponse;
 
+/**
+ * ESourceConnectionStatus:
+ * @E_SOURCE_CONNECTION_STATUS_DISCONNECTED:
+ *   The source is currently disconnected from its (possibly remote) data store.
+ * @E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS:
+ *   The source asked for credentials with a 'credentials-required' signal and
+ *   is currently awaiting for them.
+ * @E_SOURCE_CONNECTION_STATUS_SSL_FAILED:
+ *   A user rejected SSL certificate trust for the connection.
+ * @E_SOURCE_CONNECTION_STATUS_CONNECTING:
+ *   The source is currently connecting to its (possibly remote) data store.
+ * @E_SOURCE_CONNECTION_STATUS_CONNECTED:
+ *   The source is currently connected to its (possibly remote) data store.
+ *
+ * Connection status codes used by the #ESource to indicate its connection state.
+ * This is used in combination with authentication of the ESource. For example,
+ * if there are multiple clients asking for a password and a user enters the password
+ * in one of them, then the status will change into 'connecting', which is a signal
+ * do close the password prompt in the other client, because the credentials had
+ * been already provided.
+ *
+ * Since: 3.14
+ **/
+typedef enum {
+       E_SOURCE_CONNECTION_STATUS_DISCONNECTED,
+       E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS,
+       E_SOURCE_CONNECTION_STATUS_SSL_FAILED,
+       E_SOURCE_CONNECTION_STATUS_CONNECTING,
+       E_SOURCE_CONNECTION_STATUS_CONNECTED
+} ESourceConnectionStatus;
+
+/**
+ * ESourceCredentialsReason:
+ * @E_SOURCE_CREDENTIALS_REASON_UNKNOWN:
+ *   A return value when there was no 'credentials-required' signal emitted yet,
+ *   or a pair 'authenticate' signal had been received. This value should not
+ *   be used in the call of 'credentials-required'.
+ * @E_SOURCE_CREDENTIALS_REASON_REQUIRED:
+ *   This is the first attempt to get credentials for the source. It's usually
+ *   used right after the source is opened and the authentication continues with
+ *   a stored credentials, if any.
+ * @E_SOURCE_CREDENTIALS_REASON_REJECTED:
+ *   The previously used credentials had been rejected by the server. That
+ *   usually means that the user should be asked to provide/correct the credentials.
+ * @E_SOURCE_CREDENTIALS_REASON_SSL_FAILED:
+ *   A secured connection failed due to some server-side certificate issues.
+ * @E_SOURCE_CREDENTIALS_REASON_ERROR:
+ *   The server returned an error. It is not possible to connect to it
+ *   at the moment usually.
+ *
+ * An ESource's authentication reason, used by an ESource::CredentialsRequired method.
+ *
+ * Since: 3.14
+ **/
+typedef enum {
+       E_SOURCE_CREDENTIALS_REASON_UNKNOWN,
+       E_SOURCE_CREDENTIALS_REASON_REQUIRED,
+       E_SOURCE_CREDENTIALS_REASON_REJECTED,
+       E_SOURCE_CREDENTIALS_REASON_SSL_FAILED,
+       E_SOURCE_CREDENTIALS_REASON_ERROR
+} ESourceCredentialsReason;
+
 #endif /* E_SOURCE_ENUMS_H */
diff --git a/libedataserver/e-source-registry.c b/libedataserver/e-source-registry.c
index 5b37596..9d08b4e 100644
--- a/libedataserver/e-source-registry.c
+++ b/libedataserver/e-source-registry.c
@@ -54,6 +54,7 @@
 
 #include <libedataserver/e-data-server-util.h>
 #include <libedataserver/e-source-collection.h>
+#include <libedataserver/e-source-enumtypes.h>
 
 /* Needed for the defaults API. */
 #include <libedataserver/e-source-address-book.h>
@@ -61,8 +62,6 @@
 #include <libedataserver/e-source-mail-account.h>
 #include <libedataserver/e-source-mail-identity.h>
 
-#include "e-dbus-authenticator.h"
-
 #define E_SOURCE_REGISTRY_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_SOURCE_REGISTRY, ESourceRegistryPrivate))
@@ -87,10 +86,10 @@
 #define E_SETTINGS_DEFAULT_TASK_LIST_KEY       "default-task-list"
 
 typedef struct _AsyncContext AsyncContext;
-typedef struct _AuthContext AuthContext;
 typedef struct _CreateContext CreateContext;
 typedef struct _SourceClosure SourceClosure;
 typedef struct _ThreadClosure ThreadClosure;
+typedef struct _CredentialsRequiredClosure CredentialsRequiredClosure;
 
 struct _ESourceRegistryPrivate {
        GMainContext *main_context;
@@ -120,19 +119,6 @@ struct _ESourceRegistryPrivate {
 struct _AsyncContext {
        ESource *source;
        GList *list_of_sources;
-       ESourceAuthenticator *auth;
-};
-
-/* Used in e_source_registry_authenticate_sync() */
-struct _AuthContext {
-       ESourceAuthenticator *auth;
-       EDBusAuthenticator *dbus_auth;
-       GCancellable *cancellable;
-       GMainLoop *main_loop;
-       ESourceAuthenticationResult auth_result;
-       GcrSecretExchange *secret_exchange;
-       gboolean authenticating;
-       GError **error;
 };
 
 /* Used in e_source_registry_create_sources_sync() */
@@ -156,6 +142,15 @@ struct _ThreadClosure {
        GError *error;
 };
 
+struct _CredentialsRequiredClosure {
+       GWeakRef registry;
+       ESource *source;
+       ESourceCredentialsReason reason;
+       gchar *certificate_pem;
+       GTlsCertificateFlags certificate_errors;
+       GError *op_error;
+};
+
 enum {
        PROP_0,
        PROP_DEFAULT_ADDRESS_BOOK,
@@ -172,6 +167,7 @@ enum {
        SOURCE_REMOVED,
        SOURCE_ENABLED,
        SOURCE_DISABLED,
+       CREDENTIALS_REQUIRED,
        LAST_SIGNAL
 };
 
@@ -208,33 +204,9 @@ async_context_free (AsyncContext *async_context)
                async_context->list_of_sources,
                (GDestroyNotify) g_object_unref);
 
-       if (async_context->auth != NULL)
-               g_object_unref (async_context->auth);
-
        g_slice_free (AsyncContext, async_context);
 }
 
-static void
-auth_context_free (AuthContext *auth_context)
-{
-       if (auth_context->auth != NULL)
-               g_object_unref (auth_context->auth);
-
-       if (auth_context->dbus_auth != NULL)
-               g_object_unref (auth_context->dbus_auth);
-
-       if (auth_context->cancellable != NULL)
-               g_object_unref (auth_context->cancellable);
-
-       if (auth_context->main_loop != NULL)
-               g_main_loop_unref (auth_context->main_loop);
-
-       if (auth_context->secret_exchange != NULL)
-               g_object_unref (auth_context->secret_exchange);
-
-       g_slice_free (AuthContext, auth_context);
-}
-
 static CreateContext *
 create_context_new (void)
 {
@@ -292,6 +264,21 @@ thread_closure_free (ThreadClosure *closure)
        g_slice_free (ThreadClosure, closure);
 }
 
+static void
+credentials_required_closure_free (gpointer ptr)
+{
+       CredentialsRequiredClosure *closure = ptr;
+
+       if (closure) {
+               g_weak_ref_clear (&closure->registry);
+               g_object_unref (closure->source);
+               g_free (closure->certificate_pem);
+               g_clear_error (&closure->op_error);
+
+               g_slice_free (CredentialsRequiredClosure, closure);
+       }
+};
+
 G_LOCK_DEFINE_STATIC (singleton_lock);
 static GWeakRef singleton;
 
@@ -647,6 +634,55 @@ source_registry_source_notify_enabled_cb (ESource *source,
        g_source_unref (idle_source);
 }
 
+static gboolean
+source_registry_source_credentials_required_idle_cb (gpointer user_data)
+{
+       CredentialsRequiredClosure *closure = user_data;
+       ESourceRegistry *registry;
+
+       registry = g_weak_ref_get (&closure->registry);
+
+       if (registry != NULL) {
+               g_signal_emit (
+                       registry,
+                       signals[CREDENTIALS_REQUIRED], 0,
+                       closure->source, closure->reason, closure->certificate_pem,
+                       closure->certificate_errors, closure->op_error);
+
+               g_object_unref (registry);
+       }
+
+       return FALSE;
+}
+
+static void
+source_registry_source_credentials_required_cb (ESource *source,
+                                               ESourceCredentialsReason reason,
+                                               const gchar *certificate_pem,
+                                               GTlsCertificateFlags certificate_errors,
+                                               const GError *op_error,
+                                               ESourceRegistry *registry)
+{
+       GSource *idle_source;
+       CredentialsRequiredClosure *closure;
+
+       closure = g_slice_new0 (CredentialsRequiredClosure);
+       g_weak_ref_init (&closure->registry, registry);
+       closure->source = g_object_ref (source);
+       closure->reason = reason;
+       closure->certificate_pem = g_strdup (certificate_pem);
+       closure->certificate_errors = certificate_errors;
+       closure->op_error = op_error ? g_error_copy (op_error) : NULL;
+
+       idle_source = g_idle_source_new ();
+       g_source_set_callback (
+               idle_source,
+               source_registry_source_credentials_required_idle_cb,
+               closure, credentials_required_closure_free);
+       g_source_attach (idle_source, registry->priv->main_context);
+       g_source_unref (idle_source);
+}
+
 static ESource *
 source_registry_new_source (ESourceRegistry *registry,
                             GDBusObject *dbus_object)
@@ -695,6 +731,10 @@ source_registry_unref_source (ESource *source)
                source, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
                source_registry_source_notify_enabled_cb, NULL);
 
+       g_signal_handlers_disconnect_matched (
+               source, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+               source_registry_source_credentials_required_cb, NULL);
+
        g_object_unref (source);
 }
 
@@ -728,6 +768,11 @@ source_registry_add_source (ESourceRegistry *registry,
                G_CALLBACK (source_registry_source_notify_enabled_cb),
                registry);
 
+       g_signal_connect (
+               source, "credentials-required",
+               G_CALLBACK (source_registry_source_credentials_required_cb),
+               registry);
+
        g_hash_table_insert (
                registry->priv->sources,
                g_strdup (uid), g_object_ref (source));
@@ -1388,14 +1433,6 @@ source_registry_initable_init (GInitable *initable,
                goto exit;
        }
 
-       /* Allow authentication prompts for all exported data sources
-        * when a new EDBusSourceManagerProxy is created.  The thought
-        * being, if you cancel an authentication prompt you will not
-        * be bothered again until you start (or restart) a new E-D-S
-        * client app.  Failure here is non-fatal, ignore errors. */
-       e_dbus_source_manager_call_allow_auth_prompt_all_sync (
-               registry->priv->dbus_source_manager, cancellable, NULL);
-
 exit:
        registry->priv->initialized = TRUE;
        g_mutex_unlock (&registry->priv->init_lock);
@@ -1606,6 +1643,36 @@ e_source_registry_class_init (ESourceRegistryClass *class)
                NULL, NULL, NULL,
                G_TYPE_NONE, 1,
                E_TYPE_SOURCE);
+
+       /**
+        * ESourceRegistry::credentials-required:
+        * @registry: the #ESourceRegistry which emitted the signal
+        * @source: the #ESource that requires credentials
+        * @reason: an #ESourceCredentialsReason indicating why the credentials are requested
+        * @certificate_pem: PEM-encoded secure connection certificate for failed SSL checks
+        * @certificate_errors: what failed with the SSL certificate
+        * @op_error: a #GError with a description of the error, or %NULL
+        *
+        * The ::credentials-required signal is emitted when the @source
+        * requires credentials to connect to (possibly remote)
+        * data store. The credentials can be passed to the source using
+        * e_source_authenticate() function. The signal is emitted in
+        * the thread-default main context from the time the @registry was created.
+        *
+        * Note: This is just a proxy signal for the ESource::credentials-required signal.
+        **/
+       signals[CREDENTIALS_REQUIRED] = g_signal_new (
+               "credentials-required",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
+               G_STRUCT_OFFSET (ESourceRegistryClass, credentials_required),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 5,
+               E_TYPE_SOURCE,
+               E_TYPE_SOURCE_CREDENTIALS_REASON,
+               G_TYPE_STRING,
+               G_TYPE_TLS_CERTIFICATE_FLAGS,
+               G_TYPE_ERROR);
 }
 
 static void
@@ -1779,517 +1846,6 @@ e_source_registry_new_finish (GAsyncResult *result,
        return g_task_propagate_pointer (G_TASK (result), error);
 }
 
-/* Helper for e_source_registry_authenticate() */
-static void
-source_registry_authenticate_thread (GSimpleAsyncResult *simple,
-                                     GObject *object,
-                                     GCancellable *cancellable)
-{
-       AsyncContext *async_context;
-       GError *local_error = NULL;
-
-       async_context = g_simple_async_result_get_op_res_gpointer (simple);
-
-       e_source_registry_authenticate_sync (
-               E_SOURCE_REGISTRY (object),
-               async_context->source,
-               async_context->auth,
-               cancellable, &local_error);
-
-       if (local_error != NULL)
-               g_simple_async_result_take_error (simple, local_error);
-}
-
-/* Helper for e_source_registry_authenticate_sync() */
-static gboolean
-source_registry_authenticate_respond_cb (AuthContext *auth_context)
-{
-       ESourceAuthenticationResult auth_result;
-       GError *non_fatal_error = NULL;
-
-       g_return_val_if_fail (auth_context->authenticating, FALSE);
-
-       auth_result = auth_context->auth_result;
-
-       /* Allow the next authentication attempt to proceed. */
-       auth_context->authenticating = FALSE;
-
-       /* Send the server a status update based on the authentication
-        * result.  Note, we don't really care if the D-Bus message gets
-        * through to the server at this point.  If it doesn't, the auth
-        * session will either time out on its own or the authentication
-        * dialog will eventually be dismissed by the user. */
-
-       /* If we were cancelled from our side, we have a bit of a dilemma.
-        * We need to tell the server to cancel the authentication session,
-        * but that involves making a synchronous D-Bus call, which we are
-        * not supposed to do if we know we've been cancelled.  But if we
-        * don't tell the server, the authentication session will be left
-        * to timeout on its own (which may take minutes), and meanwhile
-        * all other authentication requests are blocked.  So choose the
-        * lesser evil and make the synchronous call but without passing
-        * the already-cancelled GCancellable. */
-       if (g_cancellable_is_cancelled (auth_context->cancellable)) {
-               e_dbus_authenticator_call_cancel_sync (
-                       auth_context->dbus_auth,
-                       NULL, &non_fatal_error);
-               g_main_loop_quit (auth_context->main_loop);
-
-       /* If an error occurred while attempting to authenticate,
-        * tell the server to cancel the authentication session. */
-       } else if (auth_result == E_SOURCE_AUTHENTICATION_ERROR) {
-               e_dbus_authenticator_call_cancel_sync (
-                       auth_context->dbus_auth,
-                       auth_context->cancellable,
-                       &non_fatal_error);
-               g_main_loop_quit (auth_context->main_loop);
-
-       /* If the password was accepted, let the server know so it
-        * can close any authentication dialogs and save the user
-        * provided password to the keyring. */
-       } else if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
-               e_dbus_authenticator_call_accepted_sync (
-                       auth_context->dbus_auth,
-                       auth_context->cancellable,
-                       &non_fatal_error);
-               g_main_loop_quit (auth_context->main_loop);
-
-       /* If the password was rejected, let the server know so it can
-        * indicate failure and request a different password, and then
-        * wait for the next "response" signal. */
-       } else {
-               e_dbus_authenticator_call_rejected_sync (
-                       auth_context->dbus_auth,
-                       auth_context->cancellable,
-                       &non_fatal_error);
-       }
-
-       /* Leave breadcrumbs if something went wrong,
-        * but don't fail the whole operation over it. */
-       if (non_fatal_error != NULL) {
-               g_dbus_error_strip_remote_error (non_fatal_error);
-               g_warning ("%s: %s", G_STRFUNC, non_fatal_error->message);
-               g_error_free (non_fatal_error);
-       }
-
-       return FALSE;
-}
-
-/* Helper for e_source_registry_authenticate_sync() */
-static void
-source_registry_authenticate_authenticate_cb (EDBusAuthenticator *dbus_auth,
-                                              const gchar *encrypted_secret,
-                                              AuthContext *auth_context)
-{
-       GSource *idle_source;
-       GMainContext *main_context;
-       GString *password;
-       gboolean valid_secret;
-
-       /* We should only get one secret at a time. */
-       g_return_if_fail (!auth_context->authenticating);
-
-       valid_secret = gcr_secret_exchange_receive (
-               auth_context->secret_exchange, encrypted_secret);
-       g_return_if_fail (valid_secret);
-
-       auth_context->authenticating = TRUE;
-
-       /* This avoids revealing the password in a stack trace. */
-       password = g_string_new (
-               gcr_secret_exchange_get_secret (
-               auth_context->secret_exchange, NULL));
-
-       /* Try authenticating with the given password.  We have to
-        * call this synchronously because some authenticators use
-        * mutexes to serialize I/O operations and are not prepared
-        * to make authentication attempts from a different thread.
-        *
-        * Unfortunately this means we won't notice server-side
-        * dismissals while the main loop is blocked.  We respond
-        * to the server from a low-priority idle callback so that
-        * any pending "dismissed" signals get handled first. */
-
-       auth_context->auth_result =
-               e_source_authenticator_try_password_sync (
-                       auth_context->auth, password,
-                       auth_context->cancellable,
-                       auth_context->error);
-
-       idle_source = g_idle_source_new ();
-       main_context = g_main_context_get_thread_default ();
-       g_source_set_callback (
-               idle_source, (GSourceFunc)
-               source_registry_authenticate_respond_cb,
-               auth_context, NULL);
-       g_source_attach (idle_source, main_context);
-       g_source_unref (idle_source);
-
-       g_string_free (password, TRUE);
-}
-
-/* Helper for e_source_registry_authenticate_sync() */
-static void
-source_registry_authenticate_dismissed_cb (EDBusAuthenticator *dbus_auth,
-                                           AuthContext *auth_context)
-{
-       /* Be careful not to overwrite an existing error in case this
-        * is called after e_source_authenticator_try_password_sync()
-        * but prior to the idle callback. */
-       if (auth_context->auth_result != E_SOURCE_AUTHENTICATION_ERROR) {
-               /* XXX Use a separate error code for dismissals? */
-               g_set_error_literal (
-                       auth_context->error,
-                       G_IO_ERROR, G_IO_ERROR_CANCELLED,
-                       _("The user declined to authenticate"));
-               auth_context->auth_result = E_SOURCE_AUTHENTICATION_ERROR;
-       }
-
-       g_main_loop_quit (auth_context->main_loop);
-}
-
-/* Helper for e_source_registry_authenticate_sync() */
-static void
-source_registry_authenticate_server_error_cb (EDBusAuthenticator *dbus_auth,
-                                              const gchar *name,
-                                              const gchar *message,
-                                              AuthContext *auth_context)
-{
-       /* Be careful not to overwrite an existing error */
-       if (auth_context->auth_result != E_SOURCE_AUTHENTICATION_ERROR) {
-               GError *error;
-
-               error = g_dbus_error_new_for_dbus_error (name, message);
-               g_propagate_error (auth_context->error, error);
-
-               auth_context->auth_result = E_SOURCE_AUTHENTICATION_ERROR;
-       }
-
-       g_main_loop_quit (auth_context->main_loop);
-}
-
-/* Helper for e_source_registry_authenticate_sync() */
-static gboolean
-source_registry_call_authenticate_for_source (ESourceRegistry *registry,
-                                              ESourceAuthenticator *auth,
-                                              ESource *source,
-                                              gchar **out_object_path,
-                                              GCancellable *cancellable,
-                                              GError **error)
-{
-       ESource *collection;
-       const gchar *uid;
-       gchar *prompt_title = NULL;
-       gchar *prompt_message = NULL;
-       gchar *prompt_description = NULL;
-       GError *local_error = NULL;
-
-       g_object_ref (source);
-
-       /* If the source is a member of a collection, we want to store
-        * the password under the UID of the "collection" source so it
-        * will apply to the entire collection.
-        *
-        * XXX This assumes all sources in a collection share a single
-        *     password.  If that turns out not to be true in all cases
-        *     we could maybe add a "SharedPassword: true/false" key to
-        *     [Collection] and apply it here.
-        *
-        *     Addendum: Assumption proven wrong.  GOA's generic IMAP/SMTP
-        *               provider uses a plain ECollectionBackend (backend
-        *               name "none") with separately stored passwords for
-        *               IMAP vs SMTP.  Just handle this case directly for
-        *               now, but don't rule out the "SharedPassword" idea.
-        */
-       collection = e_source_registry_find_extension (
-               registry, source, E_SOURCE_EXTENSION_COLLECTION);
-       if (collection != NULL) {
-               ESourceBackend *extension;
-               gchar *backend_name;
-
-               extension = e_source_get_extension (
-                       collection, E_SOURCE_EXTENSION_COLLECTION);
-               backend_name = e_source_backend_dup_backend_name (extension);
-
-               if (g_strcmp0 (backend_name, "none") != 0) {
-                       g_object_unref (source);
-                       source = g_object_ref (collection);
-               }
-
-               g_free (backend_name);
-
-               g_object_unref (collection);
-       }
-
-       uid = e_source_get_uid (source);
-
-       e_source_authenticator_get_prompt_strings (
-               auth, source,
-               &prompt_title,
-               &prompt_message,
-               &prompt_description);
-
-       e_dbus_source_manager_call_authenticate_sync (
-               registry->priv->dbus_source_manager, uid,
-               prompt_title, prompt_message, prompt_description,
-               out_object_path, cancellable, &local_error);
-
-       g_free (prompt_title);
-       g_free (prompt_message);
-       g_free (prompt_description);
-
-       g_object_unref (source);
-
-       if (local_error != NULL) {
-               g_dbus_error_strip_remote_error (local_error);
-               g_propagate_error (error, local_error);
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-/**
- * e_source_registry_authenticate_sync:
- * @registry: an #ESourceRegistry
- * @source: an #ESource
- * @auth: an #ESourceAuthenticator
- * @cancellable: (allow-none): optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
- *
- * Authenticates @source, using @auth to handle the authentication
- * attempts.  The operation loops until authentication is successful or
- * the user aborts further authentication attempts.  If an error occurs,
- * the function will set @error and return %FALSE.
- *
- * Note that @source need not have a #GDBusObject, which means this
- * function can test authentication on a scratch #ESource.
- *
- * Only backend implementations and data source editors should call this
- * function.  The intent is for basic client applications to not have to
- * deal with authentication at all.
- *
- * Returns: %TRUE on success, %FALSE on failure
- *
- * Since: 3.6
- **/
-gboolean
-e_source_registry_authenticate_sync (ESourceRegistry *registry,
-                                     ESource *source,
-                                     ESourceAuthenticator *auth,
-                                     GCancellable *cancellable,
-                                     GError **error)
-{
-       AuthContext *auth_context;
-       GMainContext *main_context;
-       EDBusAuthenticator *dbus_auth;
-       gboolean without_password;
-       gchar *encryption_key;
-       gchar *object_path = NULL;
-       GError *local_error = NULL;
-
-       g_return_val_if_fail (E_IS_SOURCE_REGISTRY (registry), FALSE);
-       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
-       g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth), FALSE);
-
-       /* This extracts authentication prompt details for the ESource
-        * before initiating an authentication session with the server,
-        * so split it out of the main algorithm for clarity's sake. */
-       source_registry_call_authenticate_for_source (
-               registry, auth, source, &object_path,
-               cancellable, &local_error);
-
-       if (local_error != NULL) {
-               g_warn_if_fail (object_path == NULL);
-               g_propagate_error (error, local_error);
-               return FALSE;
-       }
-
-       g_return_val_if_fail (object_path != NULL, FALSE);
-
-       main_context = g_main_context_new ();
-       g_main_context_push_thread_default (main_context);
-
-       dbus_auth = e_dbus_authenticator_proxy_new_for_bus_sync (
-               G_BUS_TYPE_SESSION,
-               G_DBUS_PROXY_FLAGS_NONE,
-               SOURCES_DBUS_SERVICE_NAME,
-               object_path, cancellable, &local_error);
-
-       g_free (object_path);
-
-       /* Sanity check. */
-       g_return_val_if_fail (
-               ((dbus_auth != NULL) && (local_error == NULL)) ||
-               ((dbus_auth == NULL) && (local_error != NULL)), FALSE);
-
-       if (local_error != NULL)
-               goto exit;
-
-       without_password = e_source_authenticator_get_without_password (auth);
-       e_dbus_authenticator_set_without_password (dbus_auth, without_password);
-
-       auth_context = g_slice_new0 (AuthContext);
-       auth_context->auth = g_object_ref (auth);
-       auth_context->dbus_auth = dbus_auth;  /* takes ownership */
-       auth_context->main_loop = g_main_loop_new (main_context, FALSE);
-       auth_context->error = &local_error;
-
-       /* This just needs to be something other than
-        * E_SOURCE_AUTHENTICATION_ERROR so we don't trip
-        * up source_registry_authenticate_dismissed_cb(). */
-       auth_context->auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
-
-       if (G_IS_CANCELLABLE (cancellable))
-               auth_context->cancellable = g_object_ref (cancellable);
-
-       auth_context->secret_exchange =
-               gcr_secret_exchange_new (GCR_SECRET_EXCHANGE_PROTOCOL_1);
-
-       g_signal_connect (
-               dbus_auth, "authenticate",
-               G_CALLBACK (source_registry_authenticate_authenticate_cb),
-               auth_context);
-
-       g_signal_connect (
-               dbus_auth, "dismissed",
-               G_CALLBACK (source_registry_authenticate_dismissed_cb),
-               auth_context);
-
-       g_signal_connect (
-               dbus_auth, "server-error",
-               G_CALLBACK (source_registry_authenticate_server_error_cb),
-               auth_context);
-
-       encryption_key = gcr_secret_exchange_begin (
-               auth_context->secret_exchange);
-
-       /* Signal the D-Bus server that we're ready to begin the
-        * authentication session.  This must happen AFTER we've
-        * connected to the response signal since the server may
-        * already have a response ready and waiting for us. */
-       e_dbus_authenticator_call_ready_sync (
-               dbus_auth, encryption_key, cancellable, &local_error);
-
-       g_free (encryption_key);
-
-       if (local_error == NULL)
-               g_main_loop_run (auth_context->main_loop);
-
-       auth_context_free (auth_context);
-
-exit:
-       g_main_context_pop_thread_default (main_context);
-
-       /* Make sure the main_context doesn't have pending operations;
-        * workarounds https://bugzilla.gnome.org/show_bug.cgi?id=690126 */
-       while (g_main_context_pending (main_context))
-               g_main_context_iteration (main_context, FALSE);
-
-       g_main_context_unref (main_context);
-
-       if (local_error != NULL) {
-               g_dbus_error_strip_remote_error (local_error);
-               g_propagate_error (error, local_error);
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-/**
- * e_source_registry_authenticate:
- * @registry: an #ESourceRegistry
- * @source: an #ESource
- * @auth: an #ESourceAuthenticator
- * @cancellable: (allow-none): optional #GCancellable object, or %NULL
- * @callback: (scope async): a #GAsyncReadyCallback to call when the request
- *            is satisfied
- * @user_data: (closure): data to pass to the callback function
- *
- * Asynchronously authenticates @source, using @auth to handle the
- * authentication attempts.  The operation loops until authentication
- * is successful or the user aborts further authentication attempts.
- *
- * Note that @source need not have a #GDBusObject, which means this
- * function can test authentication on a scratch #ESource.
- *
- * When the operation is finished, @callback will be called.  You can then
- * call e_source_registry_authenticate_finish() to get the result of the
- * operation.
- *
- * Only backend implementations and data source editors should call this
- * function.  The intent is for basic client applications to not have to
- * deal with authentication at all.
- *
- * Since: 3.6
- **/
-void
-e_source_registry_authenticate (ESourceRegistry *registry,
-                                ESource *source,
-                                ESourceAuthenticator *auth,
-                                GCancellable *cancellable,
-                                GAsyncReadyCallback callback,
-                                gpointer user_data)
-{
-       GSimpleAsyncResult *simple;
-       AsyncContext *async_context;
-
-       g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
-       g_return_if_fail (E_IS_SOURCE (source));
-       g_return_if_fail (E_IS_SOURCE_AUTHENTICATOR (auth));
-
-       async_context = g_slice_new0 (AsyncContext);
-       async_context->source = g_object_ref (source);
-       async_context->auth = g_object_ref (auth);
-
-       simple = g_simple_async_result_new (
-               G_OBJECT (registry), callback, user_data,
-               e_source_registry_authenticate);
-
-       g_simple_async_result_set_check_cancellable (simple, cancellable);
-
-       g_simple_async_result_set_op_res_gpointer (
-               simple, async_context, (GDestroyNotify) async_context_free);
-
-       g_simple_async_result_run_in_thread (
-               simple, source_registry_authenticate_thread,
-               G_PRIORITY_DEFAULT, cancellable);
-
-       g_object_unref (simple);
-}
-
-/**
- * e_source_registry_authenticate_finish:
- * @registry: an #ESourceRegistry
- * @result: a #GAsyncResult
- * @error: return location for a #GError, or %NULL
- *
- * Finishes the operation started with e_source_registry_authenticate().
- * If an error occurred, the function will set @error and return %FALSE.
- *
- * Returns: %TRUE on success, %FALSE on failure
- *
- * Since: 3.6
- **/
-gboolean
-e_source_registry_authenticate_finish (ESourceRegistry *registry,
-                                       GAsyncResult *result,
-                                       GError **error)
-{
-       GSimpleAsyncResult *simple;
-
-       g_return_val_if_fail (
-               g_simple_async_result_is_valid (
-               result, G_OBJECT (registry),
-               e_source_registry_authenticate), FALSE);
-
-       simple = G_SIMPLE_ASYNC_RESULT (result);
-
-       /* Assume success unless a GError is set. */
-       return !g_simple_async_result_propagate_error (simple, error);
-}
-
 /* Helper for e_source_registry_commit_source() */
 static void
 source_registry_commit_source_thread (GSimpleAsyncResult *simple,
diff --git a/libedataserver/e-source-registry.h b/libedataserver/e-source-registry.h
index bf47684..b3aba33 100644
--- a/libedataserver/e-source-registry.h
+++ b/libedataserver/e-source-registry.h
@@ -23,7 +23,6 @@
 #define E_SOURCE_REGISTRY_H
 
 #include <libedataserver/e-source.h>
-#include <libedataserver/e-source-authenticator.h>
 
 /* Standard GObject macros */
 #define E_TYPE_SOURCE_REGISTRY \
@@ -77,6 +76,12 @@ struct _ESourceRegistryClass {
                                                 ESource *source);
        void            (*source_disabled)      (ESourceRegistry *registry,
                                                 ESource *source);
+       void            (*credentials_required) (ESourceRegistry *registry,
+                                                ESource *source,
+                                                ESourceCredentialsReason reason,
+                                                const gchar *certificate_pem,
+                                                GTlsCertificateFlags certificate_errors,
+                                                const GError *op_error);
 };
 
 GType          e_source_registry_get_type      (void) G_GNUC_CONST;
@@ -89,22 +94,6 @@ void         e_source_registry_new           (GCancellable *cancellable,
 ESourceRegistry *
                e_source_registry_new_finish    (GAsyncResult *result,
                                                 GError **error);
-gboolean       e_source_registry_authenticate_sync
-                                               (ESourceRegistry *registry,
-                                                ESource *source,
-                                                ESourceAuthenticator *auth,
-                                                GCancellable *cancellable,
-                                                GError **error);
-void           e_source_registry_authenticate  (ESourceRegistry *registry,
-                                                ESource *source,
-                                                ESourceAuthenticator *auth,
-                                                GCancellable *cancellable,
-                                                GAsyncReadyCallback callback,
-                                                gpointer user_data);
-gboolean       e_source_registry_authenticate_finish
-                                               (ESourceRegistry *registry,
-                                                GAsyncResult *result,
-                                                GError **error);
 gboolean       e_source_registry_commit_source_sync
                                                (ESourceRegistry *registry,
                                                 ESource *source,
diff --git a/libedataserver/e-source-webdav.c b/libedataserver/e-source-webdav.c
index c30d353..efd7e55 100644
--- a/libedataserver/e-source-webdav.c
+++ b/libedataserver/e-source-webdav.c
@@ -71,7 +71,6 @@ struct _ESourceWebdavPrivate {
        gchar *ssl_trust;
        gboolean avoid_ifmatch;
        gboolean calendar_auto_schedule;
-       gboolean ignore_invalid_cert;
        SoupURI *soup_uri;
 };
 
@@ -81,7 +80,6 @@ enum {
        PROP_CALENDAR_AUTO_SCHEDULE,
        PROP_DISPLAY_NAME,
        PROP_EMAIL_ADDRESS,
-       PROP_IGNORE_INVALID_CERT,
        PROP_RESOURCE_PATH,
        PROP_RESOURCE_QUERY,
        PROP_SOUP_URI,
@@ -292,12 +290,6 @@ source_webdav_set_property (GObject *object,
                                g_value_get_string (value));
                        return;
 
-               case PROP_IGNORE_INVALID_CERT:
-                       e_source_webdav_set_ignore_invalid_cert (
-                               E_SOURCE_WEBDAV (object),
-                               g_value_get_boolean (value));
-                       return;
-
                case PROP_RESOURCE_PATH:
                        e_source_webdav_set_resource_path (
                                E_SOURCE_WEBDAV (object),
@@ -361,13 +353,6 @@ source_webdav_get_property (GObject *object,
                                E_SOURCE_WEBDAV (object)));
                        return;
 
-               case PROP_IGNORE_INVALID_CERT:
-                       g_value_set_boolean (
-                               value,
-                               e_source_webdav_get_ignore_invalid_cert (
-                               E_SOURCE_WEBDAV (object)));
-                       return;
-
                case PROP_RESOURCE_PATH:
                        g_value_take_string (
                                value,
@@ -550,18 +535,6 @@ e_source_webdav_class_init (ESourceWebdavClass *class)
 
        g_object_class_install_property (
                object_class,
-               PROP_IGNORE_INVALID_CERT,
-               g_param_spec_boolean (
-                       "ignore-invalid-cert",
-                       "Ignore Invalid Cert",
-                       "Ignore invalid SSL certificates",
-                       FALSE,
-                       G_PARAM_READWRITE |
-                       G_PARAM_CONSTRUCT |
-                       E_SOURCE_PARAM_SETTING));
-
-       g_object_class_install_property (
-               object_class,
                PROP_RESOURCE_PATH,
                g_param_spec_string (
                        "resource-path",
@@ -895,57 +868,6 @@ e_source_webdav_set_email_address (ESourceWebdav *extension,
 }
 
 /**
- * e_source_webdav_get_ignore_invalid_cert:
- * @extension: an #ESourceWebdav
- *
- * Returns %TRUE if invalid SSL certificates should be ignored.
- *
- * This option allows SSL certificates to be accepted even if they have
- * signed by an unrecognized Certificate Authority.
- *
- * Returns: whether invalid SSL certificates should be ignored
- *
- * Since: 3.6
- *
- * Deprecated: 3.8: The trust prompt APIs replace this.
- **/
-gboolean
-e_source_webdav_get_ignore_invalid_cert (ESourceWebdav *extension)
-{
-       g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), FALSE);
-
-       return extension->priv->ignore_invalid_cert;
-}
-
-/**
- * e_source_webdav_set_ignore_invalid_cert:
- * @extension: an #ESourceWebdav
- * @ignore_invalid_cert: whether invalid SSL certificates should be ignored
- *
- * Sets whether invalid SSL certificates should be ignored.
- *
- * This option allows SSL certificates to be accepted even if they have
- * signed by an unrecognized Certificate Authority.
- *
- * Since: 3.6
- *
- * Deprecated: 3.8: The trust prompt APIs replace this.
- **/
-void
-e_source_webdav_set_ignore_invalid_cert (ESourceWebdav *extension,
-                                         gboolean ignore_invalid_cert)
-{
-       g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
-
-       if (extension->priv->ignore_invalid_cert == ignore_invalid_cert)
-               return;
-
-       extension->priv->ignore_invalid_cert = ignore_invalid_cert;
-
-       g_object_notify (G_OBJECT (extension), "ignore-invalid-cert");
-}
-
-/**
  * e_source_webdav_get_resource_path:
  * @extension: an #ESourceWebdav
  *
@@ -1133,8 +1055,8 @@ e_source_webdav_set_resource_query (ESourceWebdav *extension,
  * "temporary-reject" and "temporary-accept". The second is a host
  * name for which the trust was set. Finally the last is a SHA1
  * hash of the certificate. This is not meant to be changed by a caller,
- * it is supposed to be manipulated with e_source_webdav_prepare_ssl_trust_prompt()
- * and e_source_webdav_store_ssl_trust_prompt().
+ * it is supposed to be manipulated with e_source_webdav_update_ssl_trust()
+ * and e_source_webdav_verify_ssl_trust().
  *
  * Returns: an SSL certificate trust for the @extension
  *
@@ -1367,154 +1289,83 @@ encode_ssl_trust (ESourceWebdav *extension,
 }
 
 /**
- * e_source_webdav_prepare_ssl_trust_prompt:
+ * e_source_webdav_update_ssl_trust:
  * @extension: an #ESourceWebdav
- * @message: a #SoupMessage
- * @cert: the invalid certificate of the connection over which @message is about
+ * @host: a host name to store the certificate for
+ * @cert: the invalid certificate of the connection over which @host is about
  *        to be sent
- * @cert_errors: the error flags for @cert
- * @registry: (allow-none): an #ESourceRegistry, to use for parent lookups
- * @parameters: an #ENamedParameters to be populated
- *
- * Checks @cert against currently stored trust response and either returns what
- * to do immediately, or returns #E_TRUST_PROMPT_RESPONSE_UNKNOWN and populates
- * @parameters with necessary values for a trust prompt.
- *
- * Returns: What to do with SSL connection, where
- *          #E_TRUST_PROMPT_RESPONSE_UNKNOWN means 'ask a user, with
- *          populated parameters'.
+ * @response: user's response from a trust prompt for @cert
  *
- * Note: The #E_TRUST_PROMPT_RESPONSE_REJECT is returned on any errors, such as
- *  invalid parameters.
+ * Updates user's response from a trust prompt, thus it is re-used the next
+ * time it'll be needed. An #E_TRUST_PROMPT_RESPONSE_UNKNOWN is treated as
+ * a temporary reject, which means the user will be asked again.
  *
- * Since: 3.8
+ * Since: 3.14
  **/
-ETrustPromptResponse
-e_source_webdav_prepare_ssl_trust_prompt (ESourceWebdav *extension,
-                                          SoupMessage *message,
-                                          GTlsCertificate *cert,
-                                          GTlsCertificateFlags cert_errors,
-                                          ESourceRegistry *registry,
-                                          ENamedParameters *parameters)
+void
+e_source_webdav_update_ssl_trust (ESourceWebdav *extension,
+                                 const gchar *host,
+                                 GTlsCertificate *cert,
+                                 ETrustPromptResponse response)
 {
-       ESource *parent_source = NULL;
-       ETrustPromptResponse res;
-
-       g_return_val_if_fail (
-               E_IS_SOURCE_WEBDAV (extension),
-               E_TRUST_PROMPT_RESPONSE_REJECT);
-       g_return_val_if_fail (
-               SOUP_IS_MESSAGE (message),
-               E_TRUST_PROMPT_RESPONSE_REJECT);
-       if (registry)
-               g_return_val_if_fail (
-                       E_IS_SOURCE_REGISTRY (registry),
-                       E_TRUST_PROMPT_RESPONSE_REJECT);
-       g_return_val_if_fail (
-               parameters != NULL,
-               E_TRUST_PROMPT_RESPONSE_REJECT);
-
-       if (registry != NULL) {
-               ESource *source;
-
-               source = e_source_extension_ref_source (E_SOURCE_EXTENSION (extension));
-               if (source != NULL) {
-                       const gchar *parent_uid;
-       
-                       parent_uid = e_source_get_parent (source);
-       
-                       if (parent_uid != NULL)
-                               parent_source = e_source_registry_ref_source (
-                                       registry, parent_uid);
-       
-                       g_object_unref (source);
-               }
-       }
+       GByteArray *bytes = NULL;
+       gchar *hash;
 
-       res = e_source_webdav_prepare_ssl_trust_prompt_with_parent (
-               extension, message, cert, cert_errors, parent_source, parameters);
+       g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
+       g_return_if_fail (host != NULL);
+       g_return_if_fail (cert != NULL);
 
-       if (parent_source)
-               g_object_unref (parent_source);
+       g_object_get (cert, "certificate", &bytes, NULL);
+
+       if (!bytes)
+               return;
 
-       return res;
+       hash = g_compute_checksum_for_data (G_CHECKSUM_SHA1, bytes->data, bytes->len);
+
+       encode_ssl_trust (extension, response, host, hash);
+
+       g_byte_array_unref (bytes);
+       g_free (hash);
 }
 
 /**
- * e_source_webdav_prepare_ssl_trust_prompt_with_parent:
+ * e_source_webdav_verify_ssl_trust:
  * @extension: an #ESourceWebdav
- * @message: a #SoupMessage
- * @cert: the invalid certificate of the connection over which @message is about
+ * @host: a host name to store the certificate for
+ * @cert: the invalid certificate of the connection over which @host is about
  *        to be sent
- * @cert_errors: the error flags for @cert
- * @parent_source: an #ESource, parent of the @extension<!-- -->'s source
- * @parameters: an #ENamedParameters to be populated
- *
- * The same as e_source_webdav_prepare_ssl_trust_prompt(), only takes
- * @parent_source directly, instead of an #ESourceRegistry.
- *
- * See e_source_webdav_prepare_ssl_trust_prompt() for more details.
  *
- * Since: 3.8
+ * Verifies SSL trust for the given @host and @cert, as previously stored in the @extension
+ * with e_source_webdav_update_ssl_trust().
  **/
 ETrustPromptResponse
-e_source_webdav_prepare_ssl_trust_prompt_with_parent (ESourceWebdav *extension,
-                                                      SoupMessage *message,
-                                                      GTlsCertificate *cert,
-                                                      GTlsCertificateFlags cert_errors,
-                                                      ESource *parent_source,
-                                                      ENamedParameters *parameters)
+e_source_webdav_verify_ssl_trust (ESourceWebdav *extension,
+                                 const gchar *host,
+                                 GTlsCertificate *cert,
+                                 GTlsCertificateFlags cert_errors)
 {
        ETrustPromptResponse response;
-       ESource *source;
        GByteArray *bytes = NULL;
-       SoupURI *soup_uri;
-       const gchar *host;
-       gchar *base64;
        gchar *old_host = NULL;
        gchar *old_hash = NULL;
-       gchar *cert_errs_str;
-       gchar *markup = NULL;
-
-       g_return_val_if_fail (
-               E_IS_SOURCE_WEBDAV (extension),
-               E_TRUST_PROMPT_RESPONSE_REJECT);
-       g_return_val_if_fail (
-               SOUP_IS_MESSAGE (message),
-               E_TRUST_PROMPT_RESPONSE_REJECT);
-       if (parent_source)
-               g_return_val_if_fail (
-                       E_IS_SOURCE (parent_source),
-                       E_TRUST_PROMPT_RESPONSE_REJECT);
-       g_return_val_if_fail (
-               parameters != NULL,
-               E_TRUST_PROMPT_RESPONSE_REJECT);
+
+       g_return_val_if_fail (E_IS_SOURCE_WEBDAV (extension), E_TRUST_PROMPT_RESPONSE_REJECT);
+       g_return_val_if_fail (host != NULL, E_TRUST_PROMPT_RESPONSE_REJECT);
+       g_return_val_if_fail (cert != NULL, E_TRUST_PROMPT_RESPONSE_REJECT);
 
        /* Always reject revoked certificates */
        if ((cert_errors & G_TLS_CERTIFICATE_REVOKED) != 0)
                return E_TRUST_PROMPT_RESPONSE_REJECT;
 
-       soup_uri = soup_message_get_uri (message);
-
-       if (soup_uri == NULL)
-               return E_TRUST_PROMPT_RESPONSE_REJECT;
-
-       if (soup_uri_get_host (soup_uri) == NULL)
-               return E_TRUST_PROMPT_RESPONSE_REJECT;
-
-       g_return_val_if_fail (cert != NULL, E_TRUST_PROMPT_RESPONSE_REJECT);
        g_object_get (cert, "certificate", &bytes, NULL);
 
        if (bytes == NULL)
                return E_TRUST_PROMPT_RESPONSE_REJECT;
 
-       host = soup_uri_get_host (soup_uri);
-
        if (decode_ssl_trust (extension, &response, &old_host, &old_hash)) {
                gchar *hash;
 
-               hash = g_compute_checksum_for_data (
-                       G_CHECKSUM_SHA1, bytes->data, bytes->len);
+               hash = g_compute_checksum_for_data (G_CHECKSUM_SHA1, bytes->data, bytes->len);
 
                if (response != E_TRUST_PROMPT_RESPONSE_UNKNOWN &&
                    g_strcmp0 (old_host, host) == 0 &&
@@ -1532,159 +1383,11 @@ e_source_webdav_prepare_ssl_trust_prompt_with_parent (ESourceWebdav *extension,
                g_free (hash);
        }
 
-       source = e_source_extension_ref_source (E_SOURCE_EXTENSION (extension));
-       if (source != NULL) {
-               const gchar *display_name;
-               gchar *bhost = g_strconcat ("<b>", host, "</b>", NULL);
-               gchar *bname = NULL;
-
-               display_name = e_source_get_display_name (source);
-
-               if (parent_source != NULL) {
-                       const gchar *parent_display_name;
-
-                       parent_display_name =
-                               e_source_get_display_name (parent_source);
-                       bname = g_strdup_printf (
-                               "<b>%s: %s</b>",
-                               parent_display_name, display_name);
-               }
-
-               if (bname == NULL)
-                       bname = g_strdup_printf ("<b>%s</b>", display_name);
-
-               if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
-                       /* Translators: The first %s is replaced with a host
-                        * name, like "www.example.com"; the second %s is
-                        * replaced with actual source name, like
-                        * "On The Web: My Work" */
-                       markup = g_strdup_printf (
-                               _("SSL certificate for host '%s', used by "
-                               "address book '%s', is not trusted. Do you "
-                               "wish to accept it?"), bhost, bname);
-               } else if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR)) {
-                       /* Translators: The first %s is replaced with a
-                        * host name, like "www.example.com"; the second %s
-                        * is replaced with actual source name, like
-                        * "On The Web: My Work" */
-                       markup = g_strdup_printf (
-                               _("SSL certificate for host '%s', used by "
-                               "calendar '%s', is not trusted. Do you wish "
-                               "to accept it?"), bhost, bname);
-               } else if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST)) {
-                       /* Translators: The first %s is replaced with a
-                        * host name, like "www.example.com"; the second %s
-                        * is replaced with actual source name, like
-                        * "On The Web: My Work" */
-                       markup = g_strdup_printf (
-                               _("SSL certificate for host '%s', used by "
-                               "memo list '%s', is not trusted. Do you wish "
-                               "to accept it?"), bhost, bname);
-               } else if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) {
-                       /* Translators: The first %s is replaced with a
-                        * host name, like "www.example.com"; the second %s
-                        * is replaced with actual source name, like
-                        * "On The Web: My Work" */
-                       markup = g_strdup_printf (
-                               _("SSL certificate for host '%s', used by "
-                               "task list '%s', is not trusted. Do you wish "
-                               "to accept it?"), bhost, bname);
-               }
-
-               g_object_unref (source);
-               g_free (bname);
-               g_free (bhost);
-       }
-
-       base64 = g_base64_encode (bytes->data, bytes->len);
-       cert_errs_str = g_strdup_printf ("%x", cert_errors);
-
-       e_named_parameters_set (parameters, "host", host);
-       e_named_parameters_set (parameters, "markup", markup);
-       e_named_parameters_set (parameters, "certificate", base64);
-       e_named_parameters_set (parameters, "certificate-errors", cert_errs_str);
-
        g_byte_array_unref (bytes);
-       g_free (cert_errs_str);
-       g_free (markup);
 
        return E_TRUST_PROMPT_RESPONSE_UNKNOWN;
 }
 
-static void
-webdav_extension_changes_written_cb (GObject *source_object,
-                                     GAsyncResult *result,
-                                     gpointer user_data)
-{
-       GError *error = NULL;
-
-       e_source_write_finish (E_SOURCE (source_object), result, &error);
-
-       if (error) {
-               g_message ("%s: Failed with error: %s", G_STRFUNC, error->message);
-               g_clear_error (&error);
-       }
-}
-
-/**
- * e_source_webdav_store_ssl_trust_prompt:
- * @extension: an #ESourceWebdav
- * @message: a #SoupMessage
- * @cert: the invalid certificate of the connection over which @message is about
- *        to be sent
- * @response: user's response from a trust prompt for @cert
- *
- * Stores user's response from a trust prompt, thus it is re-used the next
- * time it'll be needed. An #E_TRUST_PROMPT_RESPONSE_UNKNOWN is treated as
- * a temporary reject, which means the user will be asked again.
- *
- * Since: 3.8
- **/
-void
-e_source_webdav_store_ssl_trust_prompt (ESourceWebdav *extension,
-                                        SoupMessage *message,
-                                        GTlsCertificate *cert,
-                                        ETrustPromptResponse response)
-{
-       GByteArray *bytes = NULL;
-       SoupURI *soup_uri;
-       const gchar *host;
-       gchar *hash;
-       gboolean changed;
-
-       g_return_if_fail (E_IS_SOURCE_WEBDAV (extension));
-       g_return_if_fail (SOUP_IS_MESSAGE (message));
-
-       soup_uri = soup_message_get_uri (message);
-       if (!soup_uri || !soup_uri_get_host (soup_uri))
-               return;
-
-       g_return_if_fail (cert != NULL);
-       g_object_get (cert, "certificate", &bytes, NULL);
-
-       if (!bytes)
-               return;
-
-       host = soup_uri_get_host (soup_uri);
-       hash = g_compute_checksum_for_data (G_CHECKSUM_SHA1, bytes->data, bytes->len);
-
-       changed = encode_ssl_trust (extension, response, host, hash);
-
-       g_byte_array_unref (bytes);
-       g_free (hash);
-
-       if (changed) {
-               ESource *source;
-
-               source = e_source_extension_ref_source (
-                       E_SOURCE_EXTENSION (extension));
-               e_source_write (
-                       source, NULL,
-                       webdav_extension_changes_written_cb, NULL);
-               g_object_unref (source);
-       }
-}
-
 /**
  * e_source_webdav_unset_temporary_ssl_trust:
  * @extension: an #ESourceWebdav
diff --git a/libedataserver/e-source-webdav.h b/libedataserver/e-source-webdav.h
index 7fff9d7..e7532b1 100644
--- a/libedataserver/e-source-webdav.h
+++ b/libedataserver/e-source-webdav.h
@@ -129,38 +129,20 @@ void              e_source_webdav_set_ssl_trust   (ESourceWebdav *extension,
 SoupURI *      e_source_webdav_dup_soup_uri    (ESourceWebdav *extension);
 void           e_source_webdav_set_soup_uri    (ESourceWebdav *extension,
                                                 SoupURI *soup_uri);
-ETrustPromptResponse
-               e_source_webdav_prepare_ssl_trust_prompt
+void           e_source_webdav_update_ssl_trust
                                                (ESourceWebdav *extension,
-                                                SoupMessage *message,
+                                                const gchar *host,
                                                 GTlsCertificate *cert,
-                                                GTlsCertificateFlags cert_errors,
-                                                struct _ESourceRegistry *registry,
-                                                struct _ENamedParameters *parameters);
+                                                ETrustPromptResponse response);
 ETrustPromptResponse
-               e_source_webdav_prepare_ssl_trust_prompt_with_parent
-                                               (ESourceWebdav *extension,
-                                                SoupMessage *message,
-                                                GTlsCertificate *cert,
-                                                GTlsCertificateFlags cert_errors,
-                                                ESource *parent_source,
-                                                struct _ENamedParameters *parameters);
-void           e_source_webdav_store_ssl_trust_prompt
+               e_source_webdav_verify_ssl_trust
                                                (ESourceWebdav *extension,
-                                                SoupMessage *message,
+                                                const gchar *host,
                                                 GTlsCertificate *cert,
-                                                ETrustPromptResponse response);
+                                                GTlsCertificateFlags cert_errors);
 void           e_source_webdav_unset_temporary_ssl_trust
                                                (ESourceWebdav *extension);
 
-#ifndef EDS_DISABLE_DEPRECATED
-gboolean       e_source_webdav_get_ignore_invalid_cert
-                                               (ESourceWebdav *extension);
-void           e_source_webdav_set_ignore_invalid_cert
-                                               (ESourceWebdav *extension,
-                                                gboolean ignore_invalid_cert);
-#endif /* EDS_DISABLE_DEPRECATED */
-
 G_END_DECLS
 
 #endif /* E_SOURCE_WEBDAV_H */
diff --git a/libedataserver/e-source.c b/libedataserver/e-source.c
index 42e58a8..1a48583 100644
--- a/libedataserver/e-source.c
+++ b/libedataserver/e-source.c
@@ -77,6 +77,7 @@
 #include <e-dbus-source.h>
 
 #include "e-data-server-util.h"
+#include "e-source-enumtypes.h"
 #include "e-source-extension.h"
 #include "e-uid.h"
 
@@ -129,6 +130,13 @@ struct _ESourcePrivate {
        GSource *data_change;
        GMutex data_change_lock;
 
+       GSource *connection_status_change;
+       GMutex connection_status_change_lock;
+       ESourceConnectionStatus connection_status;
+
+       GSource *credentials_required_call;
+       GMutex credentials_required_call_lock;
+
        GMutex property_lock;
 
        gchar *display_name;
@@ -171,11 +179,14 @@ enum {
        PROP_REMOTE_DELETABLE,
        PROP_REMOVABLE,
        PROP_UID,
-       PROP_WRITABLE
+       PROP_WRITABLE,
+       PROP_CONNECTION_STATUS
 };
 
 enum {
        CHANGED,
+       CREDENTIALS_REQUIRED,
+       AUTHENTICATE,
        LAST_SIGNAL
 };
 
@@ -1032,6 +1043,211 @@ source_notify_dbus_data_cb (EDBusSource *dbus_source,
 }
 
 static gboolean
+source_update_connection_status_internal (ESource *source,
+                                         EDBusSource *dbus_source)
+{
+       ESourceConnectionStatus connection_status_value;
+       gchar *connection_status;
+       gboolean changed = FALSE;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (dbus_source != NULL, FALSE);
+
+       connection_status_value = E_SOURCE_CONNECTION_STATUS_DISCONNECTED;
+       connection_status = e_dbus_source_dup_connection_status (dbus_source);
+
+       if (connection_status) {
+               GEnumClass *enum_class;
+               GEnumValue *enum_value;
+
+               enum_class = g_type_class_ref (E_TYPE_SOURCE_CONNECTION_STATUS);
+               enum_value = g_enum_get_value_by_nick (enum_class, connection_status);
+
+               if (enum_value) {
+                       connection_status_value = enum_value->value;
+               } else if (!*connection_status) {
+                       connection_status_value = E_SOURCE_CONNECTION_STATUS_DISCONNECTED;
+               } else {
+                       g_warning ("%s: Unknown connection status: '%s'", G_STRFUNC, connection_status);
+               }
+
+               g_type_class_unref (enum_class);
+               g_free (connection_status);
+       }
+
+       if (source->priv->connection_status != connection_status_value) {
+               source->priv->connection_status = connection_status_value;
+               changed = TRUE;
+       }
+
+       return changed;
+}
+
+static gboolean
+source_idle_connection_status_change_cb (gpointer user_data)
+{
+       ESource *source = E_SOURCE (user_data);
+       EDBusObject *dbus_object;
+       EDBusSource *dbus_source;
+       gboolean changed;
+
+       /* If the ESource is still initializing itself in a different
+        * thread, skip the signal emission and try again on the next
+        * main loop iteration. This is a busy wait but it should be
+        * a very short wait. */
+       if (!source->priv->initialized)
+               return TRUE;
+
+       g_mutex_lock (&source->priv->connection_status_change_lock);
+       if (source->priv->connection_status_change != NULL) {
+               g_source_unref (source->priv->connection_status_change);
+               source->priv->connection_status_change = NULL;
+       }
+       g_mutex_unlock (&source->priv->connection_status_change_lock);
+
+       g_object_freeze_notify (G_OBJECT (source));
+       g_mutex_lock (&source->priv->property_lock);
+
+       dbus_object = E_DBUS_OBJECT (source->priv->dbus_object);
+
+       dbus_source = e_dbus_object_get_source (dbus_object);
+       changed = source_update_connection_status_internal (source, dbus_source);
+       g_object_unref (dbus_source);
+
+       if (changed)
+               g_object_notify (G_OBJECT (source), "connection-status");
+
+       g_mutex_unlock (&source->priv->property_lock);
+       g_object_thaw_notify (G_OBJECT (source));
+
+       return FALSE;
+}
+
+static void
+source_notify_dbus_connection_status_cb (EDBusSource *dbus_source,
+                                        GParamSpec *pspec,
+                                        ESource *source)
+{
+       g_mutex_lock (&source->priv->connection_status_change_lock);
+       if (source->priv->connection_status_change == NULL) {
+               source->priv->connection_status_change = g_idle_source_new ();
+               g_source_set_callback (
+                       source->priv->connection_status_change,
+                       source_idle_connection_status_change_cb,
+                       source, NULL);
+               g_source_attach (
+                       source->priv->connection_status_change,
+                       source->priv->main_context);
+       }
+       g_mutex_unlock (&source->priv->connection_status_change_lock);
+}
+
+static ESourceCredentialsReason
+source_credentials_reason_from_text (const gchar *arg_reason)
+{
+       ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
+
+       if (arg_reason && *arg_reason) {
+               GEnumClass *enum_class;
+               GEnumValue *enum_value;
+
+               enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
+               enum_value = g_enum_get_value_by_nick (enum_class, arg_reason);
+
+               if (enum_value) {
+                       reason = enum_value->value;
+               } else {
+                       g_warning ("%s: Unknown reason enum: '%s'", G_STRFUNC, arg_reason);
+               }
+
+               g_type_class_unref (enum_class);
+       }
+
+       return reason;
+}
+
+static GTlsCertificateFlags
+source_certificate_errors_from_text (const gchar *arg_certificate_errors)
+{
+       GTlsCertificateFlags certificate_errors = 0;
+
+       if (arg_certificate_errors && *arg_certificate_errors) {
+               GFlagsClass *flags_class;
+               gchar **flags_strv;
+               gsize ii;
+
+               flags_class = g_type_class_ref (G_TYPE_TLS_CERTIFICATE_FLAGS);
+               flags_strv = g_strsplit (arg_certificate_errors, ":", -1);
+               for (ii = 0; flags_strv[ii] != NULL; ii++) {
+                       GFlagsValue *flags_value;
+
+                       flags_value = g_flags_get_value_by_nick (flags_class, flags_strv[ii]);
+                       if (flags_value != NULL) {
+                               certificate_errors |= flags_value->value;
+                       } else {
+                               g_warning ("%s: Unknown flag: '%s'", G_STRFUNC, flags_strv[ii]);
+                       }
+               }
+               g_strfreev (flags_strv);
+               g_type_class_unref (flags_class);
+       }
+
+       return certificate_errors;
+}
+
+static void
+source_dbus_credentials_required_cb (EDBusSource *dbus_source,
+                                    const gchar *arg_reason,
+                                    const gchar *arg_certificate_pem,
+                                    const gchar *arg_certificate_errors,
+                                    const gchar *arg_dbus_error_name,
+                                    const gchar *arg_dbus_error_message,
+                                    ESource *source)
+{
+       ESourceCredentialsReason reason;
+       GTlsCertificateFlags certificate_errors;
+       GError *op_error = NULL;
+
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (arg_reason != NULL);
+       g_return_if_fail (arg_certificate_pem != NULL);
+       g_return_if_fail (arg_certificate_errors != NULL);
+       g_return_if_fail (arg_dbus_error_name != NULL);
+       g_return_if_fail (arg_dbus_error_message != NULL);
+
+       reason = source_credentials_reason_from_text (arg_reason);
+       certificate_errors = source_certificate_errors_from_text (arg_certificate_errors);
+
+       if (*arg_dbus_error_name) {
+               op_error = g_dbus_error_new_for_dbus_error (arg_dbus_error_name, arg_dbus_error_message);
+               g_dbus_error_strip_remote_error (op_error);
+       }
+
+       /* This is delivered in the GDBus thread */
+       e_source_emit_credentials_required (source, reason, arg_certificate_pem, certificate_errors, 
op_error);
+
+       g_clear_error (&op_error);
+}
+
+static gboolean
+source_dbus_authenticate_cb (EDBusSource *dbus_interface,
+                            const gchar *const *arg_credentials,
+                            ESource *source)
+{
+       ENamedParameters *credentials;
+
+       credentials = e_named_parameters_new_strv (arg_credentials);
+
+       /* This is delivered in the GDBus thread */
+       g_signal_emit (source, signals[AUTHENTICATE], 0, credentials);
+
+       e_named_parameters_free (credentials);
+
+       return TRUE;
+}
+
+
+static gboolean
 source_idle_changed_cb (gpointer user_data)
 {
        ESource *source = E_SOURCE (user_data);
@@ -1136,6 +1352,11 @@ source_set_property (GObject *object,
                                E_SOURCE (object),
                                g_value_get_string (value));
                        return;
+
+               case PROP_CONNECTION_STATUS:
+                       e_source_set_connection_status (E_SOURCE (object),
+                               g_value_get_enum (value));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1207,6 +1428,11 @@ source_get_property (GObject *object,
                                value, e_source_get_writable (
                                E_SOURCE (object)));
                        return;
+
+               case PROP_CONNECTION_STATUS:
+                       g_value_set_enum (value,
+                               e_source_get_connection_status (E_SOURCE (object)));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1259,6 +1485,22 @@ source_dispose (GObject *object)
        }
        g_mutex_unlock (&priv->data_change_lock);
 
+       g_mutex_lock (&priv->connection_status_change_lock);
+       if (priv->connection_status_change != NULL) {
+               g_source_destroy (priv->connection_status_change);
+               g_source_unref (priv->connection_status_change);
+               priv->connection_status_change = NULL;
+       }
+       g_mutex_unlock (&priv->connection_status_change_lock);
+
+       g_mutex_lock (&priv->credentials_required_call_lock);
+       if (priv->credentials_required_call != NULL) {
+               g_source_destroy (priv->credentials_required_call);
+               g_source_unref (priv->credentials_required_call);
+               priv->credentials_required_call = NULL;
+       }
+       g_mutex_unlock (&priv->credentials_required_call_lock);
+
        g_hash_table_remove_all (priv->extensions);
 
        /* Chain up to parent's dispose() method. */
@@ -1274,6 +1516,8 @@ source_finalize (GObject *object)
 
        g_mutex_clear (&priv->changed_lock);
        g_mutex_clear (&priv->data_change_lock);
+       g_mutex_clear (&priv->connection_status_change_lock);
+       g_mutex_clear (&priv->credentials_required_call_lock);
        g_mutex_clear (&priv->property_lock);
 
        g_free (priv->display_name);
@@ -1891,6 +2135,41 @@ source_get_oauth2_access_token_finish (ESource *source,
        return TRUE;
 }
 
+
+static gboolean
+source_invoke_credentials_required_impl (ESource *source,
+                                        gpointer dbus_source, /* EDBusSource * */
+                                        const gchar *arg_reason,
+                                        const gchar *arg_certificate_pem,
+                                        const gchar *arg_certificate_errors,
+                                        const gchar *arg_dbus_error_name,
+                                        const gchar *arg_dbus_error_message,
+                                        GCancellable *cancellable,
+                                        GError **error)
+{
+       g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
+
+       return e_dbus_source_call_invoke_credentials_required_sync (dbus_source,
+               arg_reason ? arg_reason : "",
+               arg_certificate_pem ? arg_certificate_pem : "",
+               arg_certificate_errors ? arg_certificate_errors : "",
+               arg_dbus_error_name ? arg_dbus_error_name : "",
+               arg_dbus_error_message ? arg_dbus_error_message : "",
+               cancellable, error);
+}
+
+static gboolean
+source_invoke_authenticate_impl (ESource *source,
+                                gpointer dbus_source, /* EDBusSource * */
+                                const gchar * const *arg_credentials,
+                                GCancellable *cancellable,
+                                GError **error)
+{
+       g_return_val_if_fail (E_DBUS_IS_SOURCE (dbus_source), FALSE);
+
+       return e_dbus_source_call_invoke_authenticate_sync (dbus_source, arg_credentials, cancellable, error);
+}
+
 static gboolean
 source_initable_init (GInitable *initable,
                       GCancellable *cancellable,
@@ -1922,9 +2201,20 @@ source_initable_init (GInitable *initable,
                g_free (source->priv->uid);
                source->priv->uid = e_dbus_source_dup_uid (dbus_source);
 
+               source_update_connection_status_internal (source, dbus_source);
+
                g_signal_connect (
                        dbus_source, "notify::data",
                        G_CALLBACK (source_notify_dbus_data_cb), source);
+               g_signal_connect (
+                       dbus_source, "notify::connection-status",
+                       G_CALLBACK (source_notify_dbus_connection_status_cb), source);
+               g_signal_connect (
+                       dbus_source, "credentials-required",
+                       G_CALLBACK (source_dbus_credentials_required_cb), source);
+               g_signal_connect (
+                       dbus_source, "authenticate",
+                       G_CALLBACK (source_dbus_authenticate_cb), source);
 
                success = source_parse_dbus_data (source, error);
 
@@ -2075,6 +2365,8 @@ e_source_class_init (ESourceClass *class)
        class->get_oauth2_access_token_sync = source_get_oauth2_access_token_sync;
        class->get_oauth2_access_token = source_get_oauth2_access_token;
        class->get_oauth2_access_token_finish = source_get_oauth2_access_token_finish;
+       class->invoke_credentials_required_impl = source_invoke_credentials_required_impl;
+       class->invoke_authenticate_impl = source_invoke_authenticate_impl;
 
        g_object_class_install_property (
                object_class,
@@ -2197,6 +2489,18 @@ e_source_class_init (ESourceClass *class)
                        G_PARAM_READABLE |
                        G_PARAM_STATIC_STRINGS));
 
+       g_object_class_install_property (
+               object_class,
+               PROP_CONNECTION_STATUS,
+               g_param_spec_enum (
+                       "connection-status",
+                       "Connection Status",
+                       "Connection status of the source",
+                       E_TYPE_SOURCE_CONNECTION_STATUS,
+                       E_SOURCE_CONNECTION_STATUS_DISCONNECTED,
+                       G_PARAM_READABLE |
+                       G_PARAM_STATIC_STRINGS));
+
        /**
         * ESource::changed:
         * @source: the #ESource that received the signal
@@ -2214,6 +2518,47 @@ e_source_class_init (ESourceClass *class)
                NULL, NULL, NULL,
                G_TYPE_NONE, 0);
 
+       /**
+        * ESource::credentials-required:
+        * @source: the #ESource that received the signal
+        * @reason: an #ESourceCredentialsReason indicating why the credentials are requested
+        * @certificate_pem: PEM-encoded secure connection certificate for failed SSL checks
+        * @certificate_errors: what failed with the SSL certificate
+        * @error: a text description of the error, if any
+        *
+        * The ::credentials-required signal is emitted when the @source
+        * requires credentials to connect to (possibly remote)
+        * data store. The credentials can be passed to the backend using
+        * e_source_authenticate() function.
+        **/
+       signals[CREDENTIALS_REQUIRED] = g_signal_new (
+               "credentials-required",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
+               G_STRUCT_OFFSET (ESourceClass, credentials_required),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 4,
+               E_TYPE_SOURCE_CREDENTIALS_REASON,
+               G_TYPE_STRING,
+               G_TYPE_TLS_CERTIFICATE_FLAGS,
+               G_TYPE_ERROR);
+
+       /**
+        * ESource::authenticate
+        * @source: the #ESource that received the signal
+        * @credentials: an #ENamedParameters with provided credentials
+        *
+        * Let's the backend know provided credentials to use to login
+        * to (possibly remote) data store.
+        **/
+       signals[AUTHENTICATE] = g_signal_new (
+               "authenticate",
+               G_TYPE_FROM_CLASS (class),
+               G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE,
+               G_STRUCT_OFFSET (ESourceClass, authenticate),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 1, E_TYPE_NAMED_PARAMETERS);
+
        /* Register built-in ESourceExtension types. */
        g_type_ensure (E_TYPE_SOURCE_ADDRESS_BOOK);
        g_type_ensure (E_TYPE_SOURCE_ALARMS);
@@ -2278,9 +2623,12 @@ e_source_init (ESource *source)
        source->priv = E_SOURCE_GET_PRIVATE (source);
        g_mutex_init (&source->priv->changed_lock);
        g_mutex_init (&source->priv->data_change_lock);
+       g_mutex_init (&source->priv->connection_status_change_lock);
+       g_mutex_init (&source->priv->credentials_required_call_lock);
        g_mutex_init (&source->priv->property_lock);
        source->priv->key_file = g_key_file_new ();
        source->priv->extensions = extensions;
+       source->priv->connection_status = E_SOURCE_CONNECTION_STATUS_DISCONNECTED;
 
        g_rec_mutex_init (&source->priv->lock);
 }
@@ -3205,6 +3553,68 @@ e_source_parameter_to_key (const gchar *param_name)
 }
 
 /**
+ * e_source_get_connection_status:
+ * @source: an #ESource
+ *
+ * Obtain current connection status of the @source.
+ *
+ * Returns: Current connection status of the @source.
+ *
+ * Since: 3.14
+ **/
+ESourceConnectionStatus
+e_source_get_connection_status (ESource *source)
+{
+       g_return_val_if_fail (E_IS_SOURCE (source), E_SOURCE_CONNECTION_STATUS_DISCONNECTED);
+
+       return source->priv->connection_status;
+}
+
+/**
+ * e_source_set_connection_status:
+ * @source: an #ESource
+ * @connection_status: one of the #ESourceConnectionStatus
+ *
+ * Set's current connection status of the @source.
+ *
+ * Since: 3.14
+ **/
+void
+e_source_set_connection_status (ESource *source,
+                               ESourceConnectionStatus connection_status)
+{
+       GEnumClass *enum_class;
+       GEnumValue *enum_value;
+
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       if (source->priv->connection_status == connection_status)
+               return;
+
+       source->priv->connection_status = connection_status;
+
+       enum_class = g_type_class_ref (E_TYPE_SOURCE_CONNECTION_STATUS);
+       enum_value = g_enum_get_value (enum_class, connection_status);
+
+       if (enum_value) {
+               GDBusObject *dbus_object;
+               EDBusSource *dbus_source;
+
+               dbus_object = e_source_ref_dbus_object (E_SOURCE (source));
+               dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
+               e_dbus_source_set_connection_status (dbus_source, enum_value->value_nick);
+               g_object_unref (dbus_source);
+               g_object_unref (dbus_object);
+       } else {
+               g_warning ("%s: Unknown connection status: %x", G_STRFUNC, connection_status);
+       }
+
+       g_type_class_unref (enum_class);
+
+       g_object_notify (G_OBJECT (source), "connection-status");
+}
+
+/**
  * e_source_remove_sync:
  * @source: the #ESource to be removed
  * @cancellable: (allow-none): optional #GCancellable object, or %NULL
@@ -4189,15 +4599,31 @@ e_source_delete_password_finish (ESource *source,
 }
 
 /**
- * e_source_allow_auth_prompt_sync:
+ * e_source_invoke_credentials_required_sync:
  * @source: an #ESource
- * @cancellable: optional #GCancellable object, or %NULL
- * @error: return location for a #GError, or %NULL
+ * @reason: an #ESourceCredentialsReason, why the credentials are required
+ * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
+ * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
+ * @op_error: (allow none): a #GError with a description of the previous credentials error, or %NULL
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @error: (allow none): return location for a #GError, or %NULL
  *
- * Tells the source registry that it can ask for passwords, if necessary.
- * Password prompts are disabled automatically when a user cancels
- * the password prompt. This function is to reverse the effect. It does
- * nothing, if the password prompt is not disabled.
+ * Let's the client-side know that credentials are required. The @reason defines which
+ * parameters are used. The client passed the credentials with an e_source_authenitcate()
+ * call.
+ *
+ * The %E_SOURCE_CREDENTIALS_REASON_REQUIRED is used for the first credentials prompt,
+ * when the client can return credentials as stored from the previous success login.
+ *
+ * The %E_SOURCE_CREDENTIALS_REASON_REJECTED is used when the previously used credentials
+ * had been rejected by the server. That usually means that the user should be asked
+ * to provide/correct the credentials.
+ *
+ * The %E_SOURCE_CREDENTIALS_REASON_SSL_FAILED is used when a secured connection failed
+ * due to some server-side certificate issues.
+ *
+ * The %E_SOURCE_CREDENTIALS_REASON_ERROR is used when the server returned an error.
+ * It is not possible to connect to it at the moment usually.
  *
  * If an error occurs, the function sets @error and returns %FALSE.
  *
@@ -4206,16 +4632,31 @@ e_source_delete_password_finish (ESource *source,
  * Since: 3.14
  **/
 gboolean
-e_source_allow_auth_prompt_sync (ESource *source,
-                                GCancellable *cancellable,
-                                GError **error)
+e_source_invoke_credentials_required_sync (ESource *source,
+                                          ESourceCredentialsReason reason,
+                                          const gchar *certificate_pem,
+                                          GTlsCertificateFlags certificate_errors,
+                                          const GError *op_error,
+                                          GCancellable *cancellable,
+                                          GError **error)
 {
        GDBusObject *dbus_object;
        EDBusSource *dbus_source = NULL;
+       ESourceClass *klass;
+       gchar *arg_reason, *arg_certificate_errors;
+       GEnumClass *enum_class;
+       GEnumValue *enum_value;
+       GFlagsClass *flags_class;
+       GFlagsValue *flags_value;
+       GString *certificate_errors_str;
+       gchar *dbus_error_name = NULL;
        GError *local_error = NULL;
 
        g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
 
+       klass = E_SOURCE_GET_CLASS (source);
+       g_return_val_if_fail (klass->invoke_credentials_required_impl != NULL, FALSE);
+
        dbus_object = e_source_ref_dbus_object (source);
        if (dbus_object != NULL) {
                dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
@@ -4227,8 +4668,48 @@ e_source_allow_auth_prompt_sync (ESource *source,
                return FALSE;
        }
 
-       e_dbus_source_call_allow_auth_prompt_sync (dbus_source, cancellable, &local_error);
+       enum_class = g_type_class_ref (E_TYPE_SOURCE_CREDENTIALS_REASON);
+       enum_value = g_enum_get_value (enum_class, reason);
+
+       g_return_val_if_fail (enum_value != NULL, FALSE);
+
+       arg_reason = g_strdup (enum_value->value_nick);
+       g_type_class_unref (enum_class);
+
+       certificate_errors_str = g_string_new ("");
+
+       flags_class = g_type_class_ref (G_TYPE_TLS_CERTIFICATE_FLAGS);
+       for (flags_value = g_flags_get_first_value (flags_class, certificate_errors);
+            flags_value;
+            flags_value = g_flags_get_first_value (flags_class, certificate_errors)) {
+               if (certificate_errors_str->len)
+                       g_string_append_c (certificate_errors_str, ':');
+               g_string_append (certificate_errors_str, flags_value->value_nick);
+               certificate_errors &= ~flags_value->value;
+       }
+       g_type_class_unref (flags_class);
+
+       arg_certificate_errors = g_string_free (certificate_errors_str, FALSE);
+
+       if (reason == E_SOURCE_CREDENTIALS_REASON_SSL_FAILED)
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_SSL_FAILED);
+       else if (reason != E_SOURCE_CREDENTIALS_REASON_ERROR)
+               e_source_set_connection_status (source, E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS);
 
+       if (op_error)
+               dbus_error_name = g_dbus_error_encode_gerror (op_error);
+
+       klass->invoke_credentials_required_impl (source, dbus_source,
+                       arg_reason ? arg_reason : "",
+                       certificate_pem ? certificate_pem : "",
+                       arg_certificate_errors ? arg_certificate_errors : "",
+                       dbus_error_name ? dbus_error_name : "",
+                       op_error ? op_error->message : "",
+                       cancellable, &local_error);
+
+       g_free (arg_reason);
+       g_free (arg_certificate_errors);
+       g_free (dbus_error_name);
        g_object_unref (dbus_source);
 
        if (local_error != NULL) {
@@ -4240,17 +4721,38 @@ e_source_allow_auth_prompt_sync (ESource *source,
        return TRUE;
 }
 
+typedef struct _InvokeCredentialsRequiredData {
+       ESourceCredentialsReason reason;
+       gchar *certificate_pem;
+       GTlsCertificateFlags certificate_errors;
+       GError *op_error;
+} InvokeCredentialsRequiredData;
+
+static void
+invoke_credentials_required_data_free (gpointer ptr)
+{
+       InvokeCredentialsRequiredData *data = ptr;
+
+       if (data) {
+               g_free (data->certificate_pem);
+               g_clear_error (&data->op_error);
+               g_free (data);
+       }
+}
+
 static void
-source_allow_auth_prompt_thread (GTask *task,
-                                gpointer source_object,
-                                gpointer task_data,
-                                GCancellable *cancellable)
+source_invoke_credentials_required_thread (GTask *task,
+                                          gpointer source_object,
+                                          gpointer task_data,
+                                          GCancellable *cancellable)
 {
+       InvokeCredentialsRequiredData *data = task_data;
        gboolean success;
        GError *local_error = NULL;
 
-       success = e_source_allow_auth_prompt_sync (
-               E_SOURCE (source_object),
+       success = e_source_invoke_credentials_required_sync (
+               E_SOURCE (source_object), data->reason, data->certificate_pem,
+               data->certificate_errors, data->op_error,
                cancellable, &local_error);
 
        if (local_error != NULL) {
@@ -4261,47 +4763,61 @@ source_allow_auth_prompt_thread (GTask *task,
 }
 
 /**
- * e_source_allow_auth_prompt:
+ * e_source_invoke_credentials_required:
  * @source: an #ESource
- * @cancellable: optional #GCancellable object, or %NULL
+ * @reason: an #ESourceCredentialsReason, why the credentials are required
+ * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
+ * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
+ * @op_error: (allow none): a #GError with a description of the previous credentials error, or %NULL
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
  * @callback: a #GAsyncReadyCallback to call when the request is satisfied
  * @user_data: data to pass to the callback function
  *
- * Asynchronously tells the source registry that it can ask for passwords,
- * if necessary. Password prompts are disabled automatically when a user cancels
- * the password prompt. This function is to reverse the effect. It does
- * nothing, if the password prompt is not disabled.
+ * Asynchronously calls the InvokeCredentialsRequired method on the server side,
+ * to inform clients that credentials are required.
  *
  * When the operation is finished, @callback will be called. You can then
- * call e_source_allow_auth_prompt_finish() to get the result of the operation.
+ * call e_source_invoke_credentials_required_finish() to get the result of the operation.
  *
  * Since: 3.14
  **/
 void
-e_source_allow_auth_prompt (ESource *source,
-                           GCancellable *cancellable,
-                           GAsyncReadyCallback callback,
-                           gpointer user_data)
+e_source_invoke_credentials_required (ESource *source,
+                                     ESourceCredentialsReason reason,
+                                     const gchar *certificate_pem,
+                                     GTlsCertificateFlags certificate_errors,
+                                     const GError *op_error,
+                                     GCancellable *cancellable,
+                                     GAsyncReadyCallback callback,
+                                     gpointer user_data)
 {
+       InvokeCredentialsRequiredData *data;
        GTask *task;
 
        g_return_if_fail (E_IS_SOURCE (source));
 
+       data = g_new0 (InvokeCredentialsRequiredData, 1);
+       data->reason = reason;
+       data->certificate_pem = g_strdup (certificate_pem);
+       data->certificate_errors = certificate_errors;
+       data->op_error = op_error ? g_error_copy (op_error) : NULL;
+
        task = g_task_new (source, cancellable, callback, user_data);
-       g_task_set_source_tag (task, e_source_allow_auth_prompt);
+       g_task_set_source_tag (task, e_source_invoke_credentials_required);
+       g_task_set_task_data (task, data, invoke_credentials_required_data_free);
 
-       g_task_run_in_thread (task, source_allow_auth_prompt_thread);
+       g_task_run_in_thread (task, source_invoke_credentials_required_thread);
 
        g_object_unref (task);
 }
 
 /**
- * e_source_allow_auth_prompt_finish:
+ * e_source_invoke_credentials_required_finish:
  * @source: an #ESource
  * @result: a #GAsyncResult
- * @error: return location for a #GError, or %NULL
+ * @error: (allow none): return location for a #GError, or %NULL
  *
- * Finishes the operation started with e_source_allow_auth_prompt().
+ * Finishes the operation started with e_source_invoke_credentials_required().
  *
  * If an error occurs, the function sets @error and returns %FALSE.
  *
@@ -4310,16 +4826,429 @@ e_source_allow_auth_prompt (ESource *source,
  * Since: 3.14
  **/
 gboolean
-e_source_allow_auth_prompt_finish (ESource *source,
-                                  GAsyncResult *result,
+e_source_invoke_credentials_required_finish (ESource *source,
+                                            GAsyncResult *result,
+                                            GError **error)
+{
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_source_invoke_credentials_required), FALSE);
+
+       return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+/**
+ * e_source_invoke_authenticate_sync:
+ * @source: an #ESource
+ * @credentials: (allow none): an #ENamedParameters structure with credentials to use; can be %NULL
+ *    to use those from the last call
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @error: (allow none): return location for a #GError, or %NULL
+ *
+ * Calls the InvokeAuthenticate method on the server side, thus the backend
+ * knows what credentials to use to connect to its (possibly remote) data store.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_invoke_authenticate_sync (ESource *source,
+                                  const ENamedParameters *credentials,
+                                  GCancellable *cancellable,
                                   GError **error)
 {
+       GDBusObject *dbus_object;
+       EDBusSource *dbus_source = NULL;
+       ESourceClass *klass;
+       gchar **credentials_strv;
+       gboolean success;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       klass = E_SOURCE_GET_CLASS (source);
+       g_return_val_if_fail (klass->invoke_authenticate_impl != NULL, FALSE);
+
+       dbus_object = e_source_ref_dbus_object (source);
+       if (dbus_object != NULL) {
+               dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
+               g_object_unref (dbus_object);
+       }
+
+       if (!dbus_source) {
+               g_warn_if_fail (dbus_source != NULL);
+               return FALSE;
+       }
+
+       if (credentials) {
+               if (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND) &&
+                   !e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_SSL_TRUST)) {
+                       ENamedParameters *clone;
+                       ESourceWebdav *webdav_extension;
+
+                       clone = e_named_parameters_new_clone (credentials);
+
+                       webdav_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
+                       e_named_parameters_set (clone, E_SOURCE_CREDENTIAL_SSL_TRUST,
+                               e_source_webdav_get_ssl_trust (webdav_extension));
+
+                       credentials_strv = e_named_parameters_to_strv (clone);
+
+                       e_named_parameters_free (clone);
+               } else {
+                       credentials_strv = e_named_parameters_to_strv (credentials);
+               }
+       } else {
+               ENamedParameters *empty_credentials;
+
+               empty_credentials = e_named_parameters_new ();
+               credentials_strv = e_named_parameters_to_strv (empty_credentials);
+               e_named_parameters_free (empty_credentials);
+       }
+
+       success = klass->invoke_authenticate_impl (source, dbus_source, (const gchar * const *) 
credentials_strv, cancellable, &local_error);
+
+       g_strfreev (credentials_strv);
+       g_object_unref (dbus_source);
+
+       if (local_error != NULL) {
+               g_dbus_error_strip_remote_error (local_error);
+               g_propagate_error (error, local_error);
+               return FALSE;
+       }
+
+       return success;
+}
+
+static void
+source_invoke_authenticate_thread (GTask *task,
+                                  gpointer source_object,
+                                  gpointer task_data,
+                                  GCancellable *cancellable)
+{
+       gboolean success;
+       GError *local_error = NULL;
+
+       success = e_source_invoke_authenticate_sync (
+               E_SOURCE (source_object), task_data,
+               cancellable, &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, success);
+       }
+}
+
+/**
+ * e_source_invoke_authenticate:
+ * @source: an #ESource
+ * @credentials: (allow none): an #ENamedParameters structure with credentials to use; can be %NULL
+ *    to use those from the last call
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously calls the InvokeAuthenticate method on the server side,
+ * thus the backend knows what credentials to use to connect to its (possibly
+ * remote) data store.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_source_invoke_authenticate_finish() to get the result of the operation.
+ *
+ * Since: 3.14
+ **/
+void
+e_source_invoke_authenticate (ESource *source,
+                             const ENamedParameters *credentials,
+                             GCancellable *cancellable,
+                             GAsyncReadyCallback callback,
+                             gpointer user_data)
+{
+       ENamedParameters *credentials_copy;
+       GTask *task;
+
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       credentials_copy = e_named_parameters_new_clone (credentials);
+
+       task = g_task_new (source, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_source_invoke_authenticate);
+       g_task_set_task_data (task, credentials_copy, (GDestroyNotify) e_named_parameters_free);
+
+       g_task_run_in_thread (task, source_invoke_authenticate_thread);
+
+       g_object_unref (task);
+}
+
+/**
+ * e_source_invoke_authenticate_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @error: (allow none): return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_invoke_authenticate().
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_invoke_authenticate_finish (ESource *source,
+                                    GAsyncResult *result,
+                                    GError **error)
+{
        g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
        g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
 
        g_return_val_if_fail (
                g_async_result_is_tagged (
-               result, e_source_allow_auth_prompt), FALSE);
+               result, e_source_invoke_authenticate), FALSE);
 
        return g_task_propagate_boolean (G_TASK (result), error);
 }
+
+/**
+ * e_source_emit_credentials_required:
+ * @reason: an #ESourceCredentialsReason, why the credentials are required
+ * @certificate_pem: PEM-encoded secure connection certificate, or an empty string
+ * @certificate_errors: a bit-or of #GTlsCertificateFlags for secure connection certificate
+ * @op_error: (allow none): a #GError with a description of the previous credentials error, or %NULL
+ *
+ * Emits localy (in this process only) the ESource::credentials-required
+ * signal with given parameters. That's the difference with e_source_invoke_credentials_required(),
+ * which calls the signal globally, within each client.
+ *
+ * Since: 3.14
+ **/
+void
+e_source_emit_credentials_required (ESource *source,
+                                   ESourceCredentialsReason reason,
+                                   const gchar *certificate_pem,
+                                   GTlsCertificateFlags certificate_errors,
+                                   const GError *op_error)
+{
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       g_signal_emit (source, signals[CREDENTIALS_REQUIRED], 0, reason, certificate_pem, certificate_errors, 
op_error);
+}
+
+/**
+ * e_source_get_last_credentials_required_arguments_sync:
+ * @source: an #ESource
+ * @out_reason: (out): an #ESourceCredentialsReason, why the credentials are required
+ * @out_certificate_pem: (out): PEM-encoded secure connection certificate, or an empty string
+ * @out_certificate_errors: (out): a bit-or of #GTlsCertificateFlags for secure connection certificate
+ * @out_op_error: (out): a #GError with a description of the previous credentials error
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @error: (allow none): return location for a #GError, or %NULL
+ *
+ * Retrieves the last used arguments of the 'credentials-required' signal emission.
+ * If there was none emitted yet, or a corresponding 'authenitcate' had been emitted
+ * already, then the @out_reason is set to #E_SOURCE_CREDENTIALS_REASON_UNKNOWN
+ * and the value of other 'out' arguments is set to no values.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE. The result gchar
+ * values should be freed with g_free() when no longer needed.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_get_last_credentials_required_arguments_sync (ESource *source,
+                                                      ESourceCredentialsReason *out_reason,
+                                                      gchar **out_certificate_pem,
+                                                      GTlsCertificateFlags *out_certificate_errors,
+                                                      GError **out_op_error,
+                                                      GCancellable *cancellable,
+                                                      GError **error)
+{
+       GDBusObject *dbus_object;
+       EDBusSource *dbus_source = NULL;
+       gboolean success;
+       gchar *arg_reason = NULL, *arg_certificate_errors = NULL;
+       gchar *arg_dbus_error_name = NULL, *arg_dbus_error_message = NULL;
+       GError *local_error = NULL;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (out_reason != NULL, FALSE);
+       g_return_val_if_fail (out_certificate_pem != NULL, FALSE);
+       g_return_val_if_fail (out_certificate_errors != NULL, FALSE);
+       g_return_val_if_fail (out_op_error != NULL, FALSE);
+
+       *out_reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
+       *out_certificate_pem =  NULL;
+       *out_certificate_errors = 0;
+       *out_op_error = NULL;
+
+       dbus_object = e_source_ref_dbus_object (source);
+       if (dbus_object != NULL) {
+               dbus_source = e_dbus_object_get_source (E_DBUS_OBJECT (dbus_object));
+               g_object_unref (dbus_object);
+       }
+
+       if (!dbus_source) {
+               g_warn_if_fail (dbus_source != NULL);
+               return FALSE;
+       }
+
+       success = e_dbus_source_call_get_last_credentials_required_arguments_sync (dbus_source,
+               &arg_reason, out_certificate_pem, &arg_certificate_errors,
+               &arg_dbus_error_name, &arg_dbus_error_message, cancellable, error);
+
+       g_object_unref (dbus_source);
+
+       *out_reason = source_credentials_reason_from_text (arg_reason);
+       *out_certificate_errors = source_certificate_errors_from_text (arg_certificate_errors);
+
+       if (arg_dbus_error_name && *arg_dbus_error_name && arg_dbus_error_message) {
+               *out_op_error = g_dbus_error_new_for_dbus_error (arg_dbus_error_name, arg_dbus_error_message);
+               g_dbus_error_strip_remote_error (*out_op_error);
+       }
+
+       if (*out_certificate_pem && !**out_certificate_pem) {
+               g_free (*out_certificate_pem);
+               *out_certificate_pem = NULL;
+       }
+
+       g_free (arg_reason);
+       g_free (arg_certificate_errors);
+       g_free (arg_dbus_error_name);
+       g_free (arg_dbus_error_message);
+
+       if (local_error != NULL) {
+               g_dbus_error_strip_remote_error (local_error);
+               g_propagate_error (error, local_error);
+               return FALSE;
+       }
+
+       return success;
+}
+
+static void
+source_get_last_credentials_required_arguments_thread (GTask *task,
+                                                      gpointer source_object,
+                                                      gpointer task_data,
+                                                      GCancellable *cancellable)
+{
+       InvokeCredentialsRequiredData *data;
+       GError *local_error = NULL;
+
+       data = g_new0 (InvokeCredentialsRequiredData, 1);
+       data->reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
+       data->certificate_pem = NULL;
+       data->certificate_errors = 0;
+       data->op_error = NULL;
+
+       e_source_get_last_credentials_required_arguments_sync (
+               E_SOURCE (source_object), &data->reason, &data->certificate_pem,
+               &data->certificate_errors, &data->op_error,
+               cancellable, &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_pointer (task, data, invoke_credentials_required_data_free);
+       }
+}
+
+/**
+ * e_source_get_last_credentials_required_arguments:
+ * @source: an #ESource
+ * @cancellable: (allow none): optional #GCancellable object, or %NULL
+ * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @user_data: data to pass to the callback function
+ *
+ * Asynchronously calls the GetLastCredentialsRequiredArguments method
+ * on the server side, to get the last values used for the 'credentials-required'
+ * signal. See e_source_get_last_credentials_required_arguments_sync() for
+ * more information.
+ *
+ * When the operation is finished, @callback will be called. You can then
+ * call e_source_get_last_credentials_required_arguments_finish() to get
+ * the result of the operation.
+ *
+ * Since: 3.14
+ **/
+void
+e_source_get_last_credentials_required_arguments (ESource *source,
+                                                 GCancellable *cancellable,
+                                                 GAsyncReadyCallback callback,
+                                                 gpointer user_data)
+{
+       GTask *task;
+
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       task = g_task_new (source, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_source_get_last_credentials_required_arguments);
+
+       g_task_run_in_thread (task, source_get_last_credentials_required_arguments_thread);
+
+       g_object_unref (task);
+}
+
+/**
+ * e_source_get_last_credentials_required_arguments_finish:
+ * @source: an #ESource
+ * @result: a #GAsyncResult
+ * @out_reason: (out): an #ESourceCredentialsReason, why the credentials are required
+ * @out_certificate_pem: (out): PEM-encoded secure connection certificate, or an empty string
+ * @out_certificate_errors: (out): a bit-or of #GTlsCertificateFlags for secure connection certificate
+ * @out_op_error: (out): a #GError with a description of the previous credentials error
+ * @error: (allow none): return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_source_get_last_credentials_required_arguments().
+ * See e_source_get_last_credentials_required_arguments_sync() for more information
+ * about the output arguments.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_source_get_last_credentials_required_arguments_finish (ESource *source,
+                                                        GAsyncResult *result,
+                                                        ESourceCredentialsReason *out_reason,
+                                                        gchar **out_certificate_pem,
+                                                        GTlsCertificateFlags *out_certificate_errors,
+                                                        GError **out_op_error,
+                                                        GError **error)
+{
+       InvokeCredentialsRequiredData *data;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
+       g_return_val_if_fail (out_reason != NULL, FALSE);
+       g_return_val_if_fail (out_certificate_pem != NULL, FALSE);
+       g_return_val_if_fail (out_certificate_errors != NULL, FALSE);
+       g_return_val_if_fail (out_op_error != NULL, FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_source_get_last_credentials_required_arguments), FALSE);
+
+       data = g_task_propagate_pointer (G_TASK (result), error);
+       if (!data)
+               return FALSE;
+
+       *out_reason = data->reason;
+       *out_certificate_pem =  g_strdup (data->certificate_pem);
+       *out_certificate_errors = data->certificate_errors;
+       *out_op_error = data->op_error ? g_error_copy (data->op_error) : NULL;
+
+       invoke_credentials_required_data_free (data);
+
+       return TRUE;
+}
diff --git a/libedataserver/e-source.h b/libedataserver/e-source.h
index 2d3c307..74d59d9 100644
--- a/libedataserver/e-source.h
+++ b/libedataserver/e-source.h
@@ -23,6 +23,8 @@
 #define E_SOURCE_H
 
 #include <gio/gio.h>
+#include <libedataserver/e-data-server-util.h>
+#include <libedataserver/e-source-enums.h>
 
 /* Standard GObject macros */
 #define E_TYPE_SOURCE \
@@ -54,6 +56,49 @@
  **/
 #define E_SOURCE_PARAM_SETTING (1 << G_PARAM_USER_SHIFT)
 
+/**
+ * E_SOURCE_CREDENTIAL_USERNAME:
+ *
+ * A name of the named parameter used for usernames in credentials,
+ * used to authenticate users with e_source_invoke_authenticate_sync()
+ * and e_source_invoke_authenticate(). The named parameter is optional,
+ * different authentication methods can use different names.
+ *
+ * Since: 3.14
+ **/
+#define E_SOURCE_CREDENTIAL_USERNAME "username"
+
+/**
+ * E_SOURCE_CREDENTIAL_PASSWORD:
+ *
+ * A name of the named parameter used for passwords in credentials,
+ * used to authenticate users with e_source_invoke_authenticate_sync()
+ * and e_source_invoke_authenticate(). The named parameter is optional,
+ * different authentication methods can use different names.
+ *
+ * Since: 3.14
+ **/
+#define E_SOURCE_CREDENTIAL_PASSWORD "password"
+
+/**
+ * E_SOURCE_CREDENTIAL_SSL_TRUST:
+ *
+ * A name of the named parameter used for SSL trust in credentials,
+ * used to authenticate users with e_source_invoke_authenticate_sync()
+ * and e_source_invoke_authenticate(). The named parameter is optional.
+ * Its value corresponds to current ESourceWebdav::ssl-trust property,
+ * in case the ESource has that extension available. This is required
+ * to have up-to-date data on the server side, when the client side
+ * just saved the SSL trust change, which might not be propagated
+ * into the server (factory) side quickly enough. The key is added into
+ * the credentials in invoke_authneticate() automatically, if the
+ * corresponding ESource contain a WebDAV extension and the key
+ * is not part of the credentials already.
+ *
+ * Since: 3.14
+ **/
+#define E_SOURCE_CREDENTIAL_SSL_TRUST "ssl-trust"
+
 G_BEGIN_DECLS
 
 typedef struct _ESource ESource;
@@ -78,6 +123,13 @@ struct _ESourceClass {
 
        /* Signals */
        void            (*changed)              (ESource *source);
+       void            (*credentials_required) (ESource *source,
+                                                ESourceCredentialsReason reason,
+                                                const gchar *certificate_pem,
+                                                GTlsCertificateFlags certificate_errors,
+                                                const GError *op_error);
+       void            (* authenticate)        (ESource *source,
+                                                const ENamedParameters *credentials);
 
        /* Methods */
        gboolean        (*remove_sync)          (ESource *source,
@@ -139,6 +191,22 @@ struct _ESourceClass {
                                                 gchar **out_access_token,
                                                 gint *out_expires_in,
                                                 GError **error);
+       gboolean        (*invoke_credentials_required_impl)
+                                               (ESource *source,
+                                                gpointer dbus_source, /* EDBusSource * */
+                                                const gchar *arg_reason,
+                                                const gchar *arg_certificate_pem,
+                                                const gchar *arg_certificate_errors,
+                                                const gchar *arg_dbus_error_name,
+                                                const gchar *arg_dbus_error_message,
+                                                GCancellable *cancellable,
+                                                GError **error);
+       gboolean        (*invoke_authenticate_impl)
+                                               (ESource *source,
+                                                gpointer dbus_source, /* EDBusSource * */
+                                                const gchar * const *arg_credentials,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
        /* Reserved slots. */
        gpointer reserved[7];
@@ -185,6 +253,10 @@ gint               e_source_compare_by_display_name
 gchar *                e_source_to_string              (ESource *source,
                                                 gsize *length);
 gchar *                e_source_parameter_to_key       (const gchar *param_name);
+ESourceConnectionStatus
+               e_source_get_connection_status  (ESource *source);
+void           e_source_set_connection_status  (ESource *source,
+                                                ESourceConnectionStatus connection_status);
 gboolean       e_source_remove_sync            (ESource *source,
                                                 GCancellable *cancellable,
                                                 GError **error);
@@ -282,16 +354,67 @@ void              e_source_delete_password        (ESource *source,
 gboolean       e_source_delete_password_finish (ESource *source,
                                                 GAsyncResult *result,
                                                 GError **error);
-gboolean       e_source_allow_auth_prompt_sync (ESource *source,
+gboolean       e_source_invoke_credentials_required_sync
+                                               (ESource *source,
+                                                ESourceCredentialsReason reason,
+                                                const gchar *certificate_pem,
+                                                GTlsCertificateFlags certificate_errors,
+                                                const GError *op_error,
                                                 GCancellable *cancellable,
                                                 GError **error);
-void           e_source_allow_auth_prompt      (ESource *source,
+void           e_source_invoke_credentials_required
+                                               (ESource *source,
+                                                ESourceCredentialsReason reason,
+                                                const gchar *certificate_pem,
+                                                GTlsCertificateFlags certificate_errors,
+                                                const GError *op_error,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_source_invoke_credentials_required_finish
+                                               (ESource *source,
+                                                GAsyncResult *result,
+                                                GError **error);
+gboolean       e_source_invoke_authenticate_sync
+                                               (ESource *source,
+                                                const ENamedParameters *credentials,
+                                                GCancellable *cancellable,
+                                                GError **error);
+void           e_source_invoke_authenticate    (ESource *source,
+                                                const ENamedParameters *credentials,
+                                                GCancellable *cancellable,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_source_invoke_authenticate_finish
+                                               (ESource *source,
+                                                GAsyncResult *result,
+                                                GError **error);
+void           e_source_emit_credentials_required
+                                               (ESource *source,
+                                                ESourceCredentialsReason reason,
+                                                const gchar *certificate_pem,
+                                                GTlsCertificateFlags certificate_errors,
+                                                const GError *op_error);
+gboolean       e_source_get_last_credentials_required_arguments_sync
+                                               (ESource *source,
+                                                ESourceCredentialsReason *out_reason,
+                                                gchar **out_certificate_pem,
+                                                GTlsCertificateFlags *out_certificate_errors,
+                                                GError **out_op_error,
+                                                GCancellable *cancellable,
+                                                GError **error);
+void           e_source_get_last_credentials_required_arguments
+                                               (ESource *source,
                                                 GCancellable *cancellable,
                                                 GAsyncReadyCallback callback,
                                                 gpointer user_data);
-gboolean       e_source_allow_auth_prompt_finish
+gboolean       e_source_get_last_credentials_required_arguments_finish
                                                (ESource *source,
                                                 GAsyncResult *result,
+                                                ESourceCredentialsReason *out_reason,
+                                                gchar **out_certificate_pem,
+                                                GTlsCertificateFlags *out_certificate_errors,
+                                                GError **out_op_error,
                                                 GError **error);
 
 G_END_DECLS
diff --git a/libedataserver/libedataserver-private.h b/libedataserver/libedataserver-private.h
index e71e8f4..42f366e 100644
--- a/libedataserver/libedataserver-private.h
+++ b/libedataserver/libedataserver-private.h
@@ -23,10 +23,10 @@
 
 #ifdef G_OS_WIN32
 
-const gchar *  _libedataserver_get_extensiondir
-                                               (void) G_GNUC_CONST;
-const gchar *  _libedataserver_get_imagesdir   (void) G_GNUC_CONST;
-const gchar *  _libedataserver_get_ui_uidir    (void) G_GNUC_CONST;
+const gchar *  _libedataserver_get_extensiondir        (void) G_GNUC_CONST;
+const gchar *  _libedataserver_get_imagesdir           (void) G_GNUC_CONST;
+const gchar *  _libedataserver_get_ui_uidir            (void) G_GNUC_CONST;
+const gchar *  _libedataserver_get_credentialmoduledir (void) G_GNUC_CONST;
 
 #undef E_DATA_SERVER_EXTENSIONDIR
 #define E_DATA_SERVER_EXTENSIONDIR _libedataserver_get_extensiondir ()
@@ -37,6 +37,9 @@ const gchar * _libedataserver_get_ui_uidir    (void) G_GNUC_CONST;
 #undef E_DATA_SERVER_UI_UIDIR
 #define E_DATA_SERVER_UI_UIDIR _libedataserver_get_ui_uidir ()
 
+#undef E_DATA_SERVER_CREDENTIALMODULEDIR
+#define E_DATA_SERVER_CREDENTIALMODULEDIR _libedataserver_get_credentialmoduledir ()
+
 #endif /* G_OS_WIN32 */
 
 #endif /* LIBEDATASERVER_PRIVATE_H */
diff --git a/libedataserver/libedataserver.h b/libedataserver/libedataserver.h
index 26dbe6b..989f603 100644
--- a/libedataserver/libedataserver.h
+++ b/libedataserver/libedataserver.h
@@ -27,6 +27,8 @@
 #include <libedataserver/e-credentials.h>
 #include <libedataserver/e-data-server-util.h>
 #include <libedataserver/e-debug-log.h>
+#include <libedataserver/e-extensible.h>
+#include <libedataserver/e-extension.h>
 #include <libedataserver/e-flag.h>
 #include <libedataserver/e-free-form-exp.h>
 #include <libedataserver/e-gdbus-templates.h>
@@ -34,6 +36,7 @@
 #include <libedataserver/e-list-iterator.h>
 #include <libedataserver/e-list.h>
 #include <libedataserver/e-memory.h>
+#include <libedataserver/e-module.h>
 #include <libedataserver/e-operation-pool.h>
 #include <libedataserver/e-proxy.h>
 #include <libedataserver/e-sexp.h>
@@ -45,6 +48,9 @@
 #include <libedataserver/e-source-calendar.h>
 #include <libedataserver/e-source-camel.h>
 #include <libedataserver/e-source-collection.h>
+#include <libedataserver/e-source-credentials-provider.h>
+#include <libedataserver/e-source-credentials-provider-impl.h>
+#include <libedataserver/e-source-credentials-provider-impl-password.h>
 #include <libedataserver/e-source-enums.h>
 #include <libedataserver/e-source-enumtypes.h>
 #include <libedataserver/e-source-extension.h>
diff --git a/libedataserver/libedataserver.pc.in b/libedataserver/libedataserver.pc.in
index ab07293..7c5794e 100644
--- a/libedataserver/libedataserver.pc.in
+++ b/libedataserver/libedataserver.pc.in
@@ -5,8 +5,11 @@ includedir= includedir@
 datarootdir= datarootdir@
 datadir= datadir@
 
+privlibdir= privlibdir@
 privincludedir= privincludedir@
 
+credentialmoduledir= credentialmoduledir@
+
 Name: libedataserver
 Description: Utility library for Evolution Data Server
 Version: @VERSION@
diff --git a/libedataserverui/Makefile.am b/libedataserverui/Makefile.am
new file mode 100644
index 0000000..cf625b3
--- /dev/null
+++ b/libedataserverui/Makefile.am
@@ -0,0 +1,77 @@
+BUILT_SOURCES =
+
+lib_LTLIBRARIES = libedataserverui-1.2.la
+
+libedataserverui_1_2_la_CPPFLAGS = \
+       $(AM_CPPFLAGS) \
+       -I$(top_srcdir) \
+       -I$(top_builddir) \
+       -DLIBEDATASERVERUI_COMPILATION \
+       -DG_LOG_DOMAIN=\"e-data-server-ui\" \
+       $(E_BACKEND_CFLAGS) \
+       $(E_DATA_SERVER_CFLAGS) \
+       $(CAMEL_CFLAGS) \
+       $(CODE_COVERAGE_CFLAGS) \
+       $(GNOME_PLATFORM_CFLAGS) \
+       $(GCR_BASE_CFLAGS) \
+       $(GCR_CFLAGS) \
+       $(GTK_CFLAGS) \
+       $(NULL)
+
+libedataserverui_1_2_la_LIBADD = \
+       $(top_builddir)/camel/libcamel-1.2.la \
+       $(top_builddir)/libebackend/libebackend-1.2.la \
+       $(top_builddir)/libedataserver/libedataserver-1.2.la \
+       $(E_BACKEND_LIBS) \
+       $(E_DATA_SERVER_LIBS) \
+       $(CAMEL_LIBS) \
+       $(CODE_COVERAGE_LIBS) \
+       $(GNOME_PLATFORM_LIBS) \
+       $(GCR_BASE_LIBS) \
+       $(GCR_LIBS) \
+       $(GTK_LIBS) \
+       $(NULL)
+
+libedataserverui_1_2_la_LDFLAGS = \
+       -version-info $(LIBEDATASERVERUI_CURRENT):$(LIBEDATASERVERUI_REVISION):$(LIBEDATASERVERUI_AGE) 
$(NO_UNDEFINED) \
+       $(CODE_COVERAGE_LDFLAGS) \
+       $(NULL)
+
+libedataserveruiincludedir = $(privincludedir)/libedataserverui
+
+libedataserveruiinclude_HEADERS = \
+       libedataserverui.h \
+       e-credentials-prompter.h \
+       e-credentials-prompter-impl.h \
+       e-credentials-prompter-impl-password.h \
+       e-trust-prompt.h \
+       $(NULL)
+
+libedataserverui_1_2_la_SOURCES = \
+       $(BUILT_SOURCES) \
+       e-credentials-prompter.c \
+       e-credentials-prompter-impl.c \
+       e-credentials-prompter-impl-password.c \
+       e-trust-prompt.c \
+       $(NULL)
+
+%-$(API_VERSION).pc: %.pc
+        cp $< $@
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libedataserverui-$(API_VERSION).pc
+
+EXTRA_DIST = \
+       $(pkgconfig_DATA:-$(API_VERSION).pc=.pc.in) \
+       $(NULL)
+
+CLEANFILES = $(BUILT_SOURCES)
+
+DISTCLEANFILES = \
+       $(pkgconfig_DATA) \
+       $(NULL)
+
+dist-hook:
+       cd $(distdir); rm -f $(BUILT_SOURCES)
+
+-include $(top_srcdir)/git.mk
diff --git a/libedataserverui/e-credentials-prompter-impl-password.c 
b/libedataserverui/e-credentials-prompter-impl-password.c
new file mode 100644
index 0000000..4affc7d
--- /dev/null
+++ b/libedataserverui/e-credentials-prompter-impl-password.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <gtk/gtk.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include "e-credentials-prompter.h"
+#include "e-credentials-prompter-impl-password.h"
+
+struct _ECredentialsPrompterImplPasswordPrivate {
+       gpointer prompt_id;
+       ESource *auth_source;
+       ESource *cred_source;
+       gchar *error_text;
+       ENamedParameters *credentials;
+
+       GtkDialog *dialog;
+       gulong show_dialog_idle_id;
+};
+
+G_DEFINE_TYPE (ECredentialsPrompterImplPassword, e_credentials_prompter_impl_password, 
E_TYPE_CREDENTIALS_PROMPTER_IMPL)
+
+static gboolean
+password_dialog_map_event_cb (GtkWidget *dialog,
+                             GdkEvent *event,
+                             GtkWidget *password_entry)
+{
+       gtk_widget_grab_focus (password_entry);
+
+       return FALSE;
+}
+
+static void
+credentials_prompter_impl_password_get_prompt_strings (ESource *source,
+                                                      gchar **prompt_title,
+                                                      GString **prompt_description)
+{
+       GString *description;
+       const gchar *message;
+       gchar *display_name;
+       gchar *host_name = NULL;
+
+       /* Known types */
+       enum {
+               TYPE_UNKNOWN,
+               TYPE_AMBIGUOUS,
+               TYPE_ADDRESS_BOOK,
+               TYPE_CALENDAR,
+               TYPE_MAIL_ACCOUNT,
+               TYPE_MAIL_TRANSPORT,
+               TYPE_MEMO_LIST,
+               TYPE_TASK_LIST
+       } type = TYPE_UNKNOWN;
+
+       /* XXX This is kind of a hack but it should work for now.  Build a
+        *     suitable password prompt by checking for various extensions
+        *     in the ESource.  If no recognizable extensions are found, or
+        *     if the result is ambiguous, just refer to the data source as
+        *     an "account". */
+
+       display_name = e_source_dup_display_name (source);
+
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
+               ESourceAuthentication *extension;
+
+               extension = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
+               host_name = e_source_authentication_dup_host (extension);
+       }
+
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
+               type = TYPE_ADDRESS_BOOK;
+       }
+
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR)) {
+               if (type == TYPE_UNKNOWN)
+                       type = TYPE_CALENDAR;
+               else
+                       type = TYPE_AMBIGUOUS;
+       }
+
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
+               if (type == TYPE_UNKNOWN)
+                       type = TYPE_MAIL_ACCOUNT;
+               else
+                       type = TYPE_AMBIGUOUS;
+       }
+
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
+               if (type == TYPE_UNKNOWN)
+                       type = TYPE_MAIL_TRANSPORT;
+               else
+                       type = TYPE_AMBIGUOUS;
+       }
+
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST)) {
+               if (type == TYPE_UNKNOWN)
+                       type = TYPE_MEMO_LIST;
+               else
+                       type = TYPE_AMBIGUOUS;
+       }
+
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) {
+               if (type == TYPE_UNKNOWN)
+                       type = TYPE_TASK_LIST;
+               else
+                       type = TYPE_AMBIGUOUS;
+       }
+
+       switch (type) {
+               case TYPE_ADDRESS_BOOK:
+                       message = _("Address book authentication request");
+                       break;
+               case TYPE_CALENDAR:
+               case TYPE_MEMO_LIST:
+               case TYPE_TASK_LIST:
+                       message = _("Calendar authentication request");
+                       break;
+               case TYPE_MAIL_ACCOUNT:
+               case TYPE_MAIL_TRANSPORT:
+                       message = _("Mail authentication request");
+                       break;
+               default:  /* generic account prompt */
+                       message = _("Authentication request");
+                       break;
+       }
+
+       description = g_string_sized_new (256);
+
+       g_string_append_printf (description, "<big><b>%s</b></big>\n\n", message);
+
+       switch (type) {
+               case TYPE_ADDRESS_BOOK:
+                       g_string_append_printf (description,
+                               _("Please enter the password for address book \"%s\"."), display_name);
+                       break;
+               case TYPE_CALENDAR:
+                       g_string_append_printf (description,
+                               _("Please enter the password for calendar \"%s\"."), display_name);
+                       break;
+               case TYPE_MAIL_ACCOUNT:
+                       g_string_append_printf (description,
+                               _("Please enter the password for mail account \"%s\"."), display_name);
+                       break;
+               case TYPE_MAIL_TRANSPORT:
+                       g_string_append_printf (description,
+                               _("Please enter the password for mail transport \"%s\"."), display_name);
+                       break;
+               case TYPE_MEMO_LIST:
+                       g_string_append_printf (description,
+                               _("Please enter the password for memo list \"%s\"."), display_name);
+                       break;
+               case TYPE_TASK_LIST:
+                       g_string_append_printf (description,
+                               _("Please enter the password for task list \"%s\"."), display_name);
+                       break;
+               default:  /* generic account prompt */
+                       g_string_append_printf (description,
+                               _("Please enter the password for account \"%s\"."), display_name);
+                       break;
+       }
+
+       if (host_name != NULL)
+               g_string_append_printf (
+                       description, "\n(host: %s)", host_name);
+
+       *prompt_title = g_strdup (message);
+       *prompt_description = description;
+
+       g_free (display_name);
+       g_free (host_name);
+}
+
+static gboolean
+e_credentials_prompter_impl_password_show_dialog (ECredentialsPrompterImplPassword *prompter_password)
+{
+       GtkWidget *dialog, *content_area, *widget;
+       GtkGrid *grid;
+       GtkEntry *username_entry = NULL;
+       GtkEntry *password_entry;
+       GtkToggleButton *remember_toggle = NULL;
+       GtkWindow *dialog_parent;
+       ECredentialsPrompter *prompter;
+       gchar *title;
+       GString *info_markup;
+       gint row = 0;
+       ESourceAuthentication *auth_extension = NULL;
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL_PASSWORD (prompter_password), FALSE);
+       g_return_val_if_fail (prompter_password->priv->prompt_id != NULL, FALSE);
+       g_return_val_if_fail (prompter_password->priv->dialog == NULL, FALSE);
+
+       prompter = e_credentials_prompter_impl_get_credentials_prompter (E_CREDENTIALS_PROMPTER_IMPL 
(prompter_password));
+       g_return_val_if_fail (prompter != NULL, FALSE);
+
+       dialog_parent = e_credentials_prompter_get_dialog_parent (prompter);
+
+       credentials_prompter_impl_password_get_prompt_strings (prompter_password->priv->auth_source, &title, 
&info_markup);
+       if (prompter_password->priv->error_text && *prompter_password->priv->error_text) {
+               gchar *escaped = g_markup_printf_escaped ("%s", prompter_password->priv->error_text);
+
+               g_string_append_printf (info_markup, "\n\n%s", escaped);
+               g_free (escaped);
+       }
+
+       dialog = gtk_dialog_new_with_buttons (title, dialog_parent, GTK_DIALOG_MODAL | 
GTK_DIALOG_DESTROY_WITH_PARENT,
+               _("_Cancel"), GTK_RESPONSE_CANCEL,
+               _("_OK"), GTK_RESPONSE_OK,
+               NULL);
+
+       prompter_password->priv->dialog = GTK_DIALOG (dialog);
+       gtk_dialog_set_default_response (prompter_password->priv->dialog, GTK_RESPONSE_OK);
+       gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+       if (dialog_parent)
+               gtk_window_set_transient_for (GTK_WINDOW (dialog), dialog_parent);
+       gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ON_PARENT);
+       gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
+
+       widget = gtk_dialog_get_action_area (prompter_password->priv->dialog);
+       content_area = gtk_dialog_get_content_area (prompter_password->priv->dialog);
+
+       /* Override GtkDialog defaults */
+       gtk_box_set_spacing (GTK_BOX (widget), 12);
+       gtk_container_set_border_width (GTK_CONTAINER (widget), 0);
+       gtk_box_set_spacing (GTK_BOX (content_area), 12);
+       gtk_container_set_border_width (GTK_CONTAINER (content_area), 0);
+
+       grid = GTK_GRID (gtk_grid_new ());
+       gtk_grid_set_column_spacing (grid, 12);
+       gtk_grid_set_row_spacing (grid, 6);
+
+       gtk_box_pack_start (GTK_BOX (content_area), GTK_WIDGET (grid), FALSE, TRUE, 0);
+
+       /* Password Image */
+       widget = gtk_image_new_from_icon_name ("dialog-password", GTK_ICON_SIZE_DIALOG);
+       g_object_set (
+               G_OBJECT (widget),
+               "halign", GTK_ALIGN_START,
+               "vexpand", TRUE,
+               "valign", GTK_ALIGN_START,
+               NULL);
+
+       gtk_grid_attach (grid, widget, 0, row, 1, 1);
+
+       /* Password Label */
+       widget = gtk_label_new (NULL);
+       gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
+       gtk_label_set_markup (GTK_LABEL (widget), info_markup->str);
+       g_object_set (
+               G_OBJECT (widget),
+               "hexpand", TRUE,
+               "halign", GTK_ALIGN_FILL,
+               "valign", GTK_ALIGN_CENTER,
+               "width-chars", 60,
+               "max-width-chars", 80,
+               "xalign", 0.0,
+               NULL);
+
+       gtk_grid_attach (grid, widget, 1, row, 1, 1);
+       row++;
+
+       if (e_source_has_extension (prompter_password->priv->cred_source, E_SOURCE_EXTENSION_AUTHENTICATION)) 
{
+               auth_extension = e_source_get_extension (prompter_password->priv->cred_source, 
E_SOURCE_EXTENSION_AUTHENTICATION);
+
+               if (e_source_get_writable (prompter_password->priv->cred_source)) {
+                       gchar *username;
+
+                       username = e_source_authentication_dup_user (auth_extension);
+                       if ((!username || !*username) &&
+                           e_source_has_extension (prompter_password->priv->cred_source, 
E_SOURCE_EXTENSION_COLLECTION)) {
+                               ESourceCollection *collection_extension;
+                               gchar *tmp;
+
+                               collection_extension = e_source_get_extension 
(prompter_password->priv->cred_source, E_SOURCE_EXTENSION_COLLECTION);
+
+                               tmp = e_source_collection_dup_identity (collection_extension);
+                               if (tmp && *tmp) {
+                                       g_free (username);
+                                       username = tmp;
+                                       tmp = NULL;
+                               }
+
+                               g_free (tmp);
+                       }
+
+                       username_entry = GTK_ENTRY (gtk_entry_new ());
+                       g_object_set (
+                               G_OBJECT (username_entry),
+                               "hexpand", TRUE,
+                               "halign", GTK_ALIGN_FILL,
+                               NULL);
+
+                       gtk_grid_attach (grid, GTK_WIDGET (username_entry), 1, row, 1, 1);
+                       row++;
+
+                       if (username && *username) {
+                               gtk_entry_set_text (username_entry, username);
+                       }
+
+                       g_free (username);
+               }
+       }
+
+       password_entry = GTK_ENTRY (gtk_entry_new ());
+       gtk_entry_set_visibility (password_entry, FALSE);
+       gtk_entry_set_activates_default (password_entry, TRUE);
+       g_object_set (
+               G_OBJECT (password_entry),
+               "hexpand", TRUE,
+               "halign", GTK_ALIGN_FILL,
+               NULL);
+       if (e_named_parameters_get (prompter_password->priv->credentials, E_SOURCE_CREDENTIAL_PASSWORD))
+               gtk_entry_set_text (password_entry, e_named_parameters_get 
(prompter_password->priv->credentials, E_SOURCE_CREDENTIAL_PASSWORD));
+
+       g_signal_connect (dialog, "map-event", G_CALLBACK (password_dialog_map_event_cb), password_entry);
+
+       gtk_grid_attach (grid, GTK_WIDGET (password_entry), 1, row, 1, 1);
+       row++;
+
+       if (username_entry && password_entry) {
+               widget = gtk_label_new_with_mnemonic (_("_User Name:"));
+               g_object_set (
+                       G_OBJECT (widget),
+                       "hexpand", FALSE,
+                       "vexpand", FALSE,
+                       "halign", GTK_ALIGN_END,
+                       "valign", GTK_ALIGN_CENTER,
+                       NULL);
+
+               gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (username_entry));
+               gtk_grid_attach (grid, widget, 0, row - 2, 1, 1);
+
+               widget = gtk_label_new_with_mnemonic (_("_Password:"));
+               g_object_set (
+                       G_OBJECT (widget),
+                       "hexpand", FALSE,
+                       "vexpand", FALSE,
+                       "halign", GTK_ALIGN_END,
+                       "valign", GTK_ALIGN_CENTER,
+                       NULL);
+
+               gtk_label_set_mnemonic_widget (GTK_LABEL (widget), GTK_WIDGET (password_entry));
+
+               gtk_grid_attach (grid, widget, 0, row - 1, 1, 1);
+       }
+
+       if (auth_extension) {
+               /* Remember password check */
+               widget = gtk_check_button_new_with_mnemonic (_("_Add this password to your keyring"));
+               remember_toggle = GTK_TOGGLE_BUTTON (widget);
+               gtk_toggle_button_set_active (remember_toggle, e_source_authentication_get_remember_password 
(auth_extension));
+               g_object_set (
+                       G_OBJECT (widget),
+                       "hexpand", TRUE,
+                       "halign", GTK_ALIGN_FILL,
+                       "valign", GTK_ALIGN_FILL,
+                       "margin-top", 12,
+                       NULL);
+
+               gtk_grid_attach (grid, widget, 1, row, 1, 1);
+       }
+
+       gtk_widget_show_all (GTK_WIDGET (grid));
+
+       success = gtk_dialog_run (prompter_password->priv->dialog) == GTK_RESPONSE_OK;
+
+       if (success) {
+               if (username_entry)
+                       e_named_parameters_set (prompter_password->priv->credentials,
+                               E_SOURCE_CREDENTIAL_USERNAME, gtk_entry_get_text (username_entry));
+               e_named_parameters_set (prompter_password->priv->credentials,
+                       E_SOURCE_CREDENTIAL_PASSWORD, gtk_entry_get_text (password_entry));
+
+               if (auth_extension && remember_toggle) {
+                       e_source_authentication_set_remember_password (auth_extension,
+                               gtk_toggle_button_get_active (remember_toggle));
+               }
+       }
+
+       gtk_widget_destroy (dialog);
+       prompter_password->priv->dialog = NULL;
+
+       g_string_free (info_markup, TRUE);
+       g_free (title);
+
+       return success;
+}
+
+static void
+e_credentials_prompter_impl_password_free_prompt_data (ECredentialsPrompterImplPassword *prompter_password)
+{
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL_PASSWORD (prompter_password));
+
+       prompter_password->priv->prompt_id = NULL;
+
+       g_clear_object (&prompter_password->priv->auth_source);
+       g_clear_object (&prompter_password->priv->cred_source);
+
+       g_free (prompter_password->priv->error_text);
+       prompter_password->priv->error_text = NULL;
+
+       e_named_parameters_free (prompter_password->priv->credentials);
+       prompter_password->priv->credentials = NULL;
+}
+
+static gboolean
+e_credentials_prompter_impl_password_show_dialog_idle_cb (gpointer user_data)
+{
+       ECredentialsPrompterImplPassword *prompter_password = user_data;
+
+       if (g_source_is_destroyed (g_main_current_source ()))
+               return FALSE;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL_PASSWORD (prompter_password), FALSE);
+
+       if (g_source_get_id (g_main_current_source ()) == prompter_password->priv->show_dialog_idle_id) {
+               gboolean success;
+
+               prompter_password->priv->show_dialog_idle_id = 0;
+
+               g_warn_if_fail (prompter_password->priv->dialog == NULL);
+
+               success = e_credentials_prompter_impl_password_show_dialog (prompter_password);
+
+               e_credentials_prompter_impl_prompt_finish (
+                       E_CREDENTIALS_PROMPTER_IMPL (prompter_password),
+                       prompter_password->priv->prompt_id,
+                       success ? prompter_password->priv->credentials : NULL);
+
+               e_credentials_prompter_impl_password_free_prompt_data (prompter_password);
+       }
+
+       return FALSE;
+}
+
+static void
+e_credentials_prompter_impl_password_process_prompt (ECredentialsPrompterImpl *prompter_impl,
+                                                    gpointer prompt_id,
+                                                    ESource *auth_source,
+                                                    ESource *cred_source,
+                                                    const gchar *error_text,
+                                                    const ENamedParameters *credentials)
+{
+       ECredentialsPrompterImplPassword *prompter_password;
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL_PASSWORD (prompter_impl));
+
+       prompter_password = E_CREDENTIALS_PROMPTER_IMPL_PASSWORD (prompter_impl);
+       g_return_if_fail (prompter_password->priv->prompt_id == NULL);
+       g_return_if_fail (prompter_password->priv->show_dialog_idle_id == 0);
+
+       prompter_password->priv->prompt_id = prompt_id;
+       prompter_password->priv->auth_source = g_object_ref (auth_source);
+       prompter_password->priv->cred_source = g_object_ref (cred_source);
+       prompter_password->priv->error_text = g_strdup (error_text);
+       prompter_password->priv->credentials = e_named_parameters_new_clone (credentials);
+       prompter_password->priv->show_dialog_idle_id = g_idle_add (
+               e_credentials_prompter_impl_password_show_dialog_idle_cb,
+               prompter_password);
+}
+
+static void
+e_credentials_prompter_impl_password_cancel_prompt (ECredentialsPrompterImpl *prompter_impl,
+                                                   gpointer prompt_id)
+{
+       ECredentialsPrompterImplPassword *prompter_password;
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL_PASSWORD (prompter_impl));
+
+       prompter_password = E_CREDENTIALS_PROMPTER_IMPL_PASSWORD (prompter_impl);
+       g_return_if_fail (prompter_password->priv->prompt_id == prompt_id);
+
+       /* This also closes the dialog. */
+       gtk_dialog_response (prompter_password->priv->dialog, GTK_RESPONSE_CANCEL);
+}
+
+static void
+e_credentials_prompter_impl_password_dispose (GObject *object)
+{
+       ECredentialsPrompterImplPassword *prompter_password = E_CREDENTIALS_PROMPTER_IMPL_PASSWORD (object);
+
+       if (prompter_password->priv->show_dialog_idle_id) {
+               g_source_remove (prompter_password->priv->show_dialog_idle_id);
+               prompter_password->priv->show_dialog_idle_id = 0;
+       }
+
+       g_warn_if_fail (prompter_password->priv->prompt_id == NULL);
+       g_warn_if_fail (prompter_password->priv->dialog == NULL);
+
+       e_credentials_prompter_impl_password_free_prompt_data (prompter_password);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_credentials_prompter_impl_password_parent_class)->dispose (object);
+}
+
+static void
+e_credentials_prompter_impl_password_class_init (ECredentialsPrompterImplPasswordClass *class)
+{
+       static const gchar *authentication_methods[] = {
+               "",  /* register as the default credentials prompter */
+               NULL
+       };
+
+       GObjectClass *object_class;
+       ECredentialsPrompterImplClass *prompter_impl_class;
+
+       g_type_class_add_private (class, sizeof (ECredentialsPrompterImplPasswordPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->dispose = e_credentials_prompter_impl_password_dispose;
+
+       prompter_impl_class = E_CREDENTIALS_PROMPTER_IMPL_CLASS (class);
+       prompter_impl_class->authentication_methods = (const gchar * const *) authentication_methods;
+       prompter_impl_class->process_prompt = e_credentials_prompter_impl_password_process_prompt;
+       prompter_impl_class->cancel_prompt = e_credentials_prompter_impl_password_cancel_prompt;
+}
+
+static void
+e_credentials_prompter_impl_password_init (ECredentialsPrompterImplPassword *prompter_password)
+{
+       prompter_password->priv = G_TYPE_INSTANCE_GET_PRIVATE (prompter_password,
+               E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD, ECredentialsPrompterImplPasswordPrivate);
+}
+
+/**
+ * e_credentials_prompter_impl_password_new:
+ *
+ * Creates a new instance of an #ECredentialsPrompterImplPassword.
+ *
+ * Returns: (transfer full): a newly created #ECredentialsPrompterImplPassword,
+ *    which should be freed with g_object_unref() when no longer needed.
+ *
+ * Since: 3.14
+ **/
+ECredentialsPrompterImpl *
+e_credentials_prompter_impl_password_new (void)
+{
+       return g_object_new (E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD, NULL);
+}
diff --git a/libedataserverui/e-credentials-prompter-impl-password.h 
b/libedataserverui/e-credentials-prompter-impl-password.h
new file mode 100644
index 0000000..dd3a839
--- /dev/null
+++ b/libedataserverui/e-credentials-prompter-impl-password.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined (__LIBEDATASERVERUI_H_INSIDE__) && !defined (LIBEDATASERVERUI_COMPILATION)
+#error "Only <libedataserverui/libedataserverui.h> should be included directly."
+#endif
+
+#ifndef E_CREDENTIALS_PROMPTER_IMPL_PASSWORD_H
+#define E_CREDENTIALS_PROMPTER_IMPL_PASSWORD_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libedataserverui/e-credentials-prompter-impl.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD \
+       (e_credentials_prompter_impl_password_get_type ())
+#define E_CREDENTIALS_PROMPTER_IMPL_PASSWORD(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD, ECredentialsPrompterImplPassword))
+#define E_CREDENTIALS_PROMPTER_IMPL_PASSWORD_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD, ECredentialsPrompterImplPasswordClass))
+#define E_IS_CREDENTIALS_PROMPTER_IMPL_PASSWORD(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD))
+#define E_IS_CREDENTIALS_PROMPTER_IMPL_PASSWORD_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD))
+#define E_CREDENTIALS_PROMPTER_IMPL_PASSWORD_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD, ECredentialsPrompterImplPasswordClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECredentialsPrompterImplPassword ECredentialsPrompterImplPassword;
+typedef struct _ECredentialsPrompterImplPasswordClass ECredentialsPrompterImplPasswordClass;
+typedef struct _ECredentialsPrompterImplPasswordPrivate ECredentialsPrompterImplPasswordPrivate;
+
+/**
+ * ECredentialsPrompterImplPassword:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.14
+ **/
+struct _ECredentialsPrompterImplPassword {
+       ECredentialsPrompterImpl parent;
+       ECredentialsPrompterImplPasswordPrivate *priv;
+};
+
+struct _ECredentialsPrompterImplPasswordClass {
+       ECredentialsPrompterImplClass parent_class;
+};
+
+GType          e_credentials_prompter_impl_password_get_type   (void) G_GNUC_CONST;
+ECredentialsPrompterImpl *
+               e_credentials_prompter_impl_password_new        (void);
+
+G_END_DECLS
+
+#endif /* E_CREDENTIALS_PROMPTER_IMPL_PASSWORD_H */
diff --git a/libedataserverui/e-credentials-prompter-impl.c b/libedataserverui/e-credentials-prompter-impl.c
new file mode 100644
index 0000000..11b6eaf
--- /dev/null
+++ b/libedataserverui/e-credentials-prompter-impl.c
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-credentials-prompter.h"
+#include "e-credentials-prompter-impl.h"
+
+struct _ECredentialsPrompterImplPrivate {
+       GCancellable *cancellable;
+};
+
+enum {
+       PROMPT_FINISHED,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_ABSTRACT_TYPE (ECredentialsPrompterImpl, e_credentials_prompter_impl, E_TYPE_EXTENSION)
+
+static void
+e_credentials_prompter_impl_constructed (GObject *object)
+{
+       ECredentialsPrompterImpl *prompter_impl = E_CREDENTIALS_PROMPTER_IMPL (object);
+       ECredentialsPrompterImplClass *klass;
+       ECredentialsPrompter *prompter;
+       gint ii;
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_credentials_prompter_impl_parent_class)->constructed (object);
+
+       prompter = E_CREDENTIALS_PROMPTER (e_extension_get_extensible (E_EXTENSION (prompter_impl)));
+
+       klass = E_CREDENTIALS_PROMPTER_IMPL_GET_CLASS (object);
+       g_return_if_fail (klass->authentication_methods != NULL);
+
+       for (ii = 0; klass->authentication_methods[ii]; ii++) {
+               e_credentials_prompter_register_impl (prompter, klass->authentication_methods[ii], 
prompter_impl);
+       }
+}
+
+static void
+e_credentials_prompter_impl_dispose (GObject *object)
+{
+       ECredentialsPrompterImpl *prompter_impl = E_CREDENTIALS_PROMPTER_IMPL (object);
+
+       if (prompter_impl->priv->cancellable) {
+               g_cancellable_cancel (prompter_impl->priv->cancellable);
+               g_clear_object (&prompter_impl->priv->cancellable);
+       }
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_credentials_prompter_impl_parent_class)->dispose (object);
+}
+
+static void
+e_credentials_prompter_impl_class_init (ECredentialsPrompterImplClass *klass)
+{
+       GObjectClass *object_class;
+       EExtensionClass *extension_class;
+
+       g_type_class_add_private (klass, sizeof (ECredentialsPrompterImplPrivate));
+
+       object_class = G_OBJECT_CLASS (klass);
+       object_class->dispose = e_credentials_prompter_impl_dispose;
+       object_class->constructed = e_credentials_prompter_impl_constructed;
+
+       extension_class = E_EXTENSION_CLASS (klass);
+       extension_class->extensible_type = E_TYPE_CREDENTIALS_PROMPTER;
+
+       /**
+        * ECredentialsPrompterImpl::prompt-finished:
+        * @prompter_impl: an #ECredentialsPrompterImpl which emitted the signal
+        * @prompt_id: an ID of the prompt which was finished
+        * @credentials: (allow none): entered credentials, or %NULL for cancelled prompts
+        *
+        * Emitted when a prompt of ID @prompt_id is finished.
+        *
+        * Since: 3.14
+        **/
+       signals[PROMPT_FINISHED] = g_signal_new (
+               "prompt-finished",
+               G_OBJECT_CLASS_TYPE (object_class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (ECredentialsPrompterImplClass, prompt_finished),
+               NULL, NULL, NULL,
+               G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER);
+}
+
+static void
+e_credentials_prompter_impl_init (ECredentialsPrompterImpl *prompter_impl)
+{
+       prompter_impl->priv = G_TYPE_INSTANCE_GET_PRIVATE (prompter_impl,
+               E_TYPE_CREDENTIALS_PROMPTER_IMPL, ECredentialsPrompterImplPrivate);
+
+       prompter_impl->priv->cancellable = g_cancellable_new ();
+}
+
+/**
+ * e_credentials_prompter_impl_get_credentials_prompter:
+ * @prompter_impl: an #ECredentialsPrompterImpl
+ *
+ * Returns an #ECredentialsPrompter with which the @prompter_impl is associated.
+ *
+ * Returns: an #ECredentialsPrompter
+ *
+ * Since: 3.14
+ **/
+ECredentialsPrompter *
+e_credentials_prompter_impl_get_credentials_prompter (ECredentialsPrompterImpl *prompter_impl)
+{
+       EExtensible *extensible;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl), NULL);
+
+       extensible = e_extension_get_extensible (E_EXTENSION (prompter_impl));
+       if (!extensible)
+               return NULL;
+
+       return E_CREDENTIALS_PROMPTER (extensible);
+}
+
+/**
+ * e_credentials_prompter_impl_prompt:
+ * @prompter_impl: an #ECredentialsPrompterImpl
+ * @prompt_id: a prompt ID to be passed to e_credentials_prompter_impl_prompt_finish()
+ * @auth_source: an #ESource, to prompt the credentials for (the source which asked for credentials)
+ * @cred_source: a parent #ESource, from which credentials were taken, or should be stored to
+ * @error_text: (allow none): an optional error text from the previous credentials prompt; can be %NULL
+ * @credentials: credentials, as saved in keyring; can be empty, but not %NULL
+ *
+ * Runs a credentials prompt for the @prompter_impl. The actual prompter implementation
+ * receives the prompt through ECredentialsPrompterImplClass::process_prompt(), where the given
+ * @prompt_id is used for an identification. The prompt is left 'active' as long as it is
+ * not finished with a call of e_credentials_prompter_impl_prompt_finish(). This should be
+ * called even for cancelled prompts. The prompt can be cancelled before it's processed,
+ * using the e_credentials_prompter_impl_cancel_prompt().
+ *
+ * The @auth_source can be the same as @cred_source, in case the credentials
+ * are stored only for that particular source. If the sources share credentials,
+ * which can be a case when the @auth_source is part of a collection, then
+ * the @cred_stource can be that collection source.
+ *
+ * Since: 3.14
+ **/
+void
+e_credentials_prompter_impl_prompt (ECredentialsPrompterImpl *prompter_impl,
+                                   gpointer prompt_id,
+                                   ESource *auth_source,
+                                   ESource *cred_source,
+                                   const gchar *error_text,
+                                   const ENamedParameters *credentials)
+{
+       ECredentialsPrompterImplClass *klass;
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl));
+       g_return_if_fail (E_IS_SOURCE (auth_source));
+       g_return_if_fail (E_IS_SOURCE (cred_source));
+       g_return_if_fail (credentials != NULL);
+
+       klass = E_CREDENTIALS_PROMPTER_IMPL_GET_CLASS (prompter_impl);
+       g_return_if_fail (klass->process_prompt != NULL);
+
+       klass->process_prompt (prompter_impl, prompt_id, auth_source, cred_source, error_text, credentials);
+}
+
+/**
+ * e_credentials_prompter_impl_prompt_finish:
+ * @prompter_impl: an #ECredentialsPrompterImpl
+ * @prompt_id: a prompt ID
+ * @credentials: (allow none): credentials to use; can be %NULL for cancelled prompts
+ *
+ * The actual credentials prompt implementation finishes a previously started
+ * credentials prompt @prompt_id with ECredentialsPrompterImplClass::process_prompt()
+ * by a call to this function. This function should be called regardless the prompt
+ * was or was not cancelled with e_credentials_prompter_impl_cancel_prompt().
+ * Once the prompt is finished another queued is started, if any pending exists.
+ * Use %NULL @credentials for cancelled prompts, otherwise the credentials are used
+ * for authentication of the associated #ESource.
+ *
+ * Since: 3.14
+ **/
+void
+e_credentials_prompter_impl_prompt_finish (ECredentialsPrompterImpl *prompter_impl,
+                                          gpointer prompt_id,
+                                          const ENamedParameters *credentials)
+{
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl));
+       g_return_if_fail (prompt_id != NULL);
+
+       g_signal_emit (prompter_impl, signals[PROMPT_FINISHED], 0, prompt_id, credentials);
+}
+
+/**
+ * e_credentials_prompter_impl_cancel_prompt:
+ * @prompter_impl: an #ECredentialsPrompterImpl
+ * @prompt_id: a prompt ID to cancel
+ *
+ * Asks the @prompt_impl to cancel current prompt, which should have ID @prompt_id.
+ *
+ * Since: 3.14
+ **/
+void
+e_credentials_prompter_impl_cancel_prompt (ECredentialsPrompterImpl *prompter_impl,
+                                          gpointer prompt_id)
+{
+       ECredentialsPrompterImplClass *klass;
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl));
+
+       klass = E_CREDENTIALS_PROMPTER_IMPL_GET_CLASS (prompter_impl);
+       g_return_if_fail (klass->cancel_prompt != NULL);
+
+       klass->cancel_prompt (prompter_impl, prompt_id);
+}
diff --git a/libedataserverui/e-credentials-prompter-impl.h b/libedataserverui/e-credentials-prompter-impl.h
new file mode 100644
index 0000000..806fa6e
--- /dev/null
+++ b/libedataserverui/e-credentials-prompter-impl.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined (__LIBEDATASERVERUI_H_INSIDE__) && !defined (LIBEDATASERVERUI_COMPILATION)
+#error "Only <libedataserverui/libedataserverui.h> should be included directly."
+#endif
+
+#ifndef E_CREDENTIALS_PROMPTER_IMPL_H
+#define E_CREDENTIALS_PROMPTER_IMPL_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <libedataserver/libedataserver.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CREDENTIALS_PROMPTER_IMPL \
+       (e_credentials_prompter_impl_get_type ())
+#define E_CREDENTIALS_PROMPTER_IMPL(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CREDENTIALS_PROMPTER_IMPL, ECredentialsPrompterImpl))
+#define E_CREDENTIALS_PROMPTER_IMPL_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CREDENTIALS_PROMPTER_IMPL, ECredentialsPrompterImplClass))
+#define E_IS_CREDENTIALS_PROMPTER_IMPL(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CREDENTIALS_PROMPTER_IMPL))
+#define E_IS_CREDENTIALS_PROMPTER_IMPL_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CREDENTIALS_PROMPTER_IMPL))
+#define E_CREDENTIALS_PROMPTER_IMPL_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CREDENTIALS_PROMPTER_IMPL, ECredentialsPrompterImplClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECredentialsPrompterImpl ECredentialsPrompterImpl;
+typedef struct _ECredentialsPrompterImplClass ECredentialsPrompterImplClass;
+typedef struct _ECredentialsPrompterImplPrivate ECredentialsPrompterImplPrivate;
+
+struct _ECredentialsPrompter;
+
+/**
+ * ECredentialsPrompterImpl:
+ *
+ * Credentials prompter implementation base structure. The descendants
+ * implement ECredentialsPrompterImpl::prompt(), which is used to
+ * prompt for credentials. The descendants are automatically registered
+ * into an #ECredentialsPrompter.
+ *
+ * Since: 3.14
+ **/
+struct _ECredentialsPrompterImpl {
+       EExtension parent;
+       ECredentialsPrompterImplPrivate *priv;
+};
+
+struct _ECredentialsPrompterImplClass {
+       EExtensionClass parent_class;
+
+       const gchar * const *authentication_methods; /* NULL-terminated array of methods to register with */
+
+       /* Methods */
+
+       void    (*process_prompt)       (ECredentialsPrompterImpl *prompter_impl,
+                                        gpointer prompt_id,
+                                        ESource *auth_source,
+                                        ESource *cred_source,
+                                        const gchar *error_text,
+                                        const ENamedParameters *credentials);
+       void    (*cancel_prompt)        (ECredentialsPrompterImpl *prompter_impl,
+                                        gpointer prompt_id);
+
+       /* Signals */
+
+       void    (*prompt_finished)      (ECredentialsPrompterImpl *prompter_impl,
+                                        gpointer prompt_id,
+                                        const ENamedParameters *credentials);
+};
+
+GType          e_credentials_prompter_impl_get_type    (void);
+struct _ECredentialsPrompter *
+               e_credentials_prompter_impl_get_credentials_prompter
+                                                       (ECredentialsPrompterImpl *prompter_impl);
+void           e_credentials_prompter_impl_prompt      (ECredentialsPrompterImpl *prompter_impl,
+                                                        gpointer prompt_id,
+                                                        ESource *auth_source,
+                                                        ESource *cred_source,
+                                                        const gchar *error_text,
+                                                        const ENamedParameters *credentials);
+void           e_credentials_prompter_impl_prompt_finish
+                                                       (ECredentialsPrompterImpl *prompter_impl,
+                                                        gpointer prompt_id,
+                                                        const ENamedParameters *credentials);
+void           e_credentials_prompter_impl_cancel_prompt
+                                                       (ECredentialsPrompterImpl *prompter_impl,
+                                                        gpointer prompt_id);
+
+G_END_DECLS
+
+#endif /* E_CREDENTIALS_PROMPTER_IMPL_H */
diff --git a/libedataserverui/e-credentials-prompter.c b/libedataserverui/e-credentials-prompter.c
new file mode 100644
index 0000000..f295e41
--- /dev/null
+++ b/libedataserverui/e-credentials-prompter.c
@@ -0,0 +1,1763 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#include <camel/camel.h>
+#include <libedataserver/libedataserver.h>
+
+#include "e-credentials-prompter.h"
+
+/* built-in credentials prompter implementations */
+#include "e-credentials-prompter-impl-password.h"
+
+typedef struct _ProcessPromptData {
+       GWeakRef *prompter;
+       ECredentialsPrompterImpl *prompter_impl;
+       ESource *auth_source;
+       ESource *cred_source;
+       ESourceConnectionStatus connection_status; /* of the auth_source */
+       gboolean remember_password; /* of the cred_source, to check for changes */
+       gulong notify_handler_id;
+       gchar *error_text;
+       ENamedParameters *credentials;
+       gboolean allow_source_save;
+       GSimpleAsyncResult *async_result;
+} ProcessPromptData;
+
+struct _ECredentialsPrompterPrivate {
+       ESourceRegistry *registry;
+       ESourceCredentialsProvider *provider;
+       gboolean auto_prompt;
+       GCancellable *cancellable;
+
+       GMutex disabled_auto_prompt_lock;
+       GHashTable *disabled_auto_prompt; /* gchar *source_uid ~> 1; Source UIDs for which the auto-prompt is 
disabled */
+
+       GMutex prompters_lock;
+       GHashTable *prompters;          /* gchar *method ~> ECredentialsPrompterImpl *impl */
+       GHashTable *known_prompters;    /* gpointer [ECredentialsPrompterImpl] ~> UINT known instances; the 
prompter_impl is not referenced */
+
+       GRecMutex queue_lock;           /* guards all queue and schedule related properties */
+       GSList *queue;                  /* ProcessPromptData * */
+       ProcessPromptData *processing_prompt;
+       gulong schedule_idle_id;
+};
+
+enum {
+       PROP_0,
+       PROP_AUTO_PROMPT,
+       PROP_REGISTRY,
+       PROP_PROVIDER
+};
+
+enum {
+       GET_DIALOG_PARENT,
+       LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE_WITH_CODE (ECredentialsPrompter, e_credentials_prompter, G_TYPE_OBJECT,
+       G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
+
+static void
+process_prompt_data_free (gpointer ptr)
+{
+       ProcessPromptData *ppd = ptr;
+
+       if (ppd) {
+               if (ppd->notify_handler_id > 0)
+                       g_signal_handler_disconnect (ppd->auth_source, ppd->notify_handler_id);
+
+               if (ppd->async_result) {
+                       ECredentialsPrompter *prompter;
+
+                       prompter = g_weak_ref_get (ppd->prompter);
+                       if (prompter) {
+                               e_credentials_prompter_complete_prompt_call (prompter, ppd->async_result, 
ppd->auth_source, NULL, NULL);
+                               g_clear_object (&prompter);
+                       }
+               }
+
+               e_weak_ref_free (ppd->prompter);
+               g_clear_object (&ppd->prompter_impl);
+               g_clear_object (&ppd->auth_source);
+               g_clear_object (&ppd->cred_source);
+               g_free (ppd->error_text);
+               e_named_parameters_free (ppd->credentials);
+               g_free (ppd);
+       }
+}
+
+typedef struct _LookupSourceDetailsData {
+       ESource *auth_source; /* an ESource which asked for credentials */
+       ESource *cred_source; /* this might be auth_source or a parent collection source, if applicable, from 
where the credentials come */
+       ENamedParameters *credentials; /* actual stored credentials */
+} LookupSourceDetailsData;
+
+static void
+lookup_source_details_data_free (gpointer ptr)
+{
+       LookupSourceDetailsData *data = ptr;
+
+       if (data) {
+               g_clear_object (&data->auth_source);
+               g_clear_object (&data->cred_source);
+               e_named_parameters_free (data->credentials);
+               g_free (data);
+       }
+}
+
+static void
+credentials_prompter_lookup_source_details_thread (GTask *task,
+                                                  gpointer source_object,
+                                                  gpointer task_data,
+                                                  GCancellable *cancellable)
+{
+       ESource *source, *cred_source = NULL;
+       ECredentialsPrompter *prompter;
+       ESourceCredentialsProvider *provider;
+       ENamedParameters *credentials = NULL;
+       GError *local_error = NULL;
+
+       g_return_if_fail (E_IS_SOURCE (source_object));
+
+       source = E_SOURCE (source_object);
+
+       prompter = g_weak_ref_get (task_data);
+       if (!prompter)
+               return;
+
+       provider = e_credentials_prompter_get_provider (prompter);
+       cred_source = e_source_credentials_provider_ref_credentials_source (provider, source);
+
+       e_source_credentials_provider_lookup_sync (prompter->priv->provider, cred_source ? cred_source : 
source, cancellable, &credentials, &local_error);
+
+       /* Interested only in the cancelled error, which means the prompter is freed. */
+       if (local_error != NULL && g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_task_return_error (task, local_error);
+               local_error = NULL;
+       } else {
+               LookupSourceDetailsData *data;
+
+               data = g_new0 (LookupSourceDetailsData, 1);
+               data->auth_source = g_object_ref (source);
+               data->cred_source = g_object_ref (cred_source ? cred_source : source); /* always set both, 
for simplicity */
+               data->credentials = credentials; /* NULL for no credentials available */
+
+               /* To not be freed below. */
+               credentials = NULL;
+
+               g_task_return_pointer (task, data, lookup_source_details_data_free);
+       }
+
+       e_named_parameters_free (credentials);
+       g_clear_object (&cred_source);
+       g_clear_object (&prompter);
+       g_clear_error (&local_error);
+}
+
+static void
+credentials_prompter_lookup_source_details (ESource *source,
+                                           ECredentialsPrompter *prompter,
+                                           GAsyncReadyCallback callback,
+                                           gpointer user_data)
+{
+       GTask *task;
+
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       task = g_task_new (source, prompter->priv->cancellable, callback, user_data);
+       g_task_set_source_tag (task, credentials_prompter_lookup_source_details_thread);
+       g_task_set_task_data (task, e_weak_ref_new (prompter), (GDestroyNotify) e_weak_ref_free);
+
+       g_task_run_in_thread (task, credentials_prompter_lookup_source_details_thread);
+
+       g_object_unref (task);
+}
+
+static gboolean
+credentials_prompter_lookup_source_details_finish (ESource *source,
+                                                  GAsyncResult *result,
+                                                  ECredentialsPrompter **out_prompter, /* will be 
referenced, if not NULL */
+                                                  LookupSourceDetailsData **out_data,
+                                                  GError **error)
+{
+       LookupSourceDetailsData *data;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (out_prompter != NULL, FALSE);
+       g_return_val_if_fail (out_data != NULL, FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, credentials_prompter_lookup_source_details_thread), FALSE);
+
+       data = g_task_propagate_pointer (G_TASK (result), error);
+       if (!data)
+               return FALSE;
+
+       *out_data = data;
+       *out_prompter = g_weak_ref_get (g_task_get_task_data (G_TASK (result)));
+
+       return TRUE;
+}
+
+static void
+credentials_prompter_invoke_authenticate_cb (GObject *source_object,
+                                            GAsyncResult *result,
+                                            gpointer user_data)
+{
+       GError *error = NULL;
+
+       if (!e_source_invoke_authenticate_finish (E_SOURCE (source_object), result, &error) &&
+           !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_debug ("%s: Failed to invoke authenticate: %s", G_STRFUNC, error ? error->message : 
"Unknown error");
+       }
+
+       g_clear_error (&error);
+}
+
+typedef struct _CredentialsPromptData {
+       ESource *source;
+       gchar *error_text;
+       ECredentialsPrompterPromptFlags flags;
+       GTask *complete_task;
+       GSimpleAsyncResult *async_result;
+} CredentialsPromptData;
+
+static void
+credentials_prompt_data_free (gpointer ptr)
+{
+       CredentialsPromptData *data = ptr;
+
+       if (data) {
+               if (data->async_result) {
+                       g_simple_async_result_set_error (data->async_result,
+                               G_IO_ERROR, G_IO_ERROR_CANCELLED, "%s", _("Credentials prompt was 
cancelled"));
+                       g_simple_async_result_complete_in_idle (data->async_result);
+                       g_clear_object (&data->async_result);
+               }
+
+               g_clear_object (&data->source);
+               g_free (data->error_text);
+               g_free (data);
+       }
+}
+
+typedef struct _CredentialsResultData {
+       ESource *source;
+       ENamedParameters *credentials;
+} CredentialsResultData;
+
+static void
+credentials_result_data_free (gpointer ptr)
+{
+       CredentialsResultData *data = ptr;
+
+       if (data) {
+               g_clear_object (&data->source);
+               e_named_parameters_free (data->credentials);
+               g_free (data);
+       }
+}
+
+
+static void
+credentials_prompter_maybe_process_next_prompt (ECredentialsPrompter *prompter)
+{
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       g_rec_mutex_lock (&prompter->priv->queue_lock);
+
+       /* Already processing one */
+       if (prompter->priv->processing_prompt) {
+               g_rec_mutex_unlock (&prompter->priv->queue_lock);
+               return;
+       }
+
+       if (prompter->priv->queue) {
+               ProcessPromptData *ppd = prompter->priv->queue->data;
+
+               g_warn_if_fail (ppd != NULL);
+
+               prompter->priv->queue = g_slist_remove (prompter->priv->queue, ppd);
+               prompter->priv->processing_prompt = ppd;
+
+               e_credentials_prompter_impl_prompt (ppd->prompter_impl, ppd, ppd->auth_source,
+                       ppd->cred_source, ppd->error_text, ppd->credentials);
+       }
+
+       g_rec_mutex_unlock (&prompter->priv->queue_lock);
+}
+
+static gboolean
+credentials_prompter_process_next_prompt_idle_cb (gpointer user_data)
+{
+       ECredentialsPrompter *prompter = user_data;
+
+       if (g_source_is_destroyed (g_main_current_source ()))
+               return FALSE;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), FALSE);
+
+       g_rec_mutex_lock (&prompter->priv->queue_lock);
+
+       if (g_source_get_id (g_main_current_source ()) == prompter->priv->schedule_idle_id) {
+               prompter->priv->schedule_idle_id = 0;
+
+               credentials_prompter_maybe_process_next_prompt (prompter);
+       }
+
+       g_rec_mutex_unlock (&prompter->priv->queue_lock);
+
+       return FALSE;
+}
+
+static void
+credentials_prompter_schedule_process_next_prompt (ECredentialsPrompter *prompter)
+{
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       g_rec_mutex_lock (&prompter->priv->queue_lock);
+
+       /* Already processing one */
+       if (prompter->priv->processing_prompt ||
+           prompter->priv->schedule_idle_id) {
+               g_rec_mutex_unlock (&prompter->priv->queue_lock);
+               return;
+       }
+
+       prompter->priv->schedule_idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
+               credentials_prompter_process_next_prompt_idle_cb,
+               prompter, NULL);
+
+       g_rec_mutex_unlock (&prompter->priv->queue_lock);
+}
+
+static void
+credentials_prompter_connection_status_changed_cb (ESource *source,
+                                                  GParamSpec *param,
+                                                  ECredentialsPrompter *prompter)
+{
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       /* Do not cancel the prompt when the source is still waiting for the credentials. */
+       if (e_source_get_connection_status (source) == E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS)
+               return;
+
+       g_rec_mutex_lock (&prompter->priv->queue_lock);
+
+       if (prompter->priv->processing_prompt &&
+           e_source_equal (prompter->priv->processing_prompt->auth_source, source)) {
+               e_credentials_prompter_impl_cancel_prompt (prompter->priv->processing_prompt->prompter_impl, 
prompter->priv->processing_prompt);
+       } else {
+               GSList *link;
+
+               for (link = prompter->priv->queue; link; link = g_slist_next (link)) {
+                       ProcessPromptData *ppd = link->data;
+
+                       g_warn_if_fail (ppd != NULL);
+
+                       if (ppd && e_source_equal (ppd->auth_source, source)) {
+                               if (ppd->connection_status != e_source_get_connection_status (source)) {
+                                       prompter->priv->queue = g_slist_remove (prompter->priv->queue, ppd);
+                                       process_prompt_data_free (ppd);
+                               }
+                               break;
+                       }
+               }
+       }
+
+       g_rec_mutex_unlock (&prompter->priv->queue_lock);
+}
+
+static gboolean
+e_credentials_prompter_eval_remember_password (ESource *source)
+{
+       gboolean remember_password = FALSE;
+
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION))
+               remember_password = e_source_authentication_get_remember_password (
+                       e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION));
+
+       return remember_password;
+}
+
+static void
+e_credentials_prompter_manage_impl_prompt (ECredentialsPrompter *prompter,
+                                          ECredentialsPrompterImpl *prompter_impl,
+                                          ESource *auth_source,
+                                          ESource *cred_source,
+                                          const gchar *error_text,
+                                          const ENamedParameters *credentials,
+                                          gboolean allow_source_save,
+                                          GSimpleAsyncResult *async_result)
+{
+       GSList *link;
+       gboolean success = TRUE;
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl));
+       g_return_if_fail (E_IS_SOURCE (auth_source));
+       g_return_if_fail (E_IS_SOURCE (cred_source));
+       g_return_if_fail (credentials != NULL);
+
+       g_rec_mutex_lock (&prompter->priv->queue_lock);
+
+       for (link = prompter->priv->queue; link; link = g_slist_next (link)) {
+               ProcessPromptData *ppd = link->data;
+
+               g_warn_if_fail (ppd != NULL);
+
+               if (ppd && e_source_equal (ppd->auth_source, auth_source)) {
+                       break;
+               }
+       }
+
+       if (link != NULL || (prompter->priv->processing_prompt &&
+           e_source_equal (prompter->priv->processing_prompt->auth_source, auth_source))) {
+               /* have queued or already asking for credentials for this source */
+               success = FALSE;
+       } else {
+               ProcessPromptData *ppd;
+
+               ppd = g_new0 (ProcessPromptData, 1);
+               ppd->prompter = e_weak_ref_new (prompter);
+               ppd->prompter_impl = g_object_ref (prompter_impl);
+               ppd->auth_source = g_object_ref (auth_source);
+               ppd->cred_source = g_object_ref (cred_source);
+               ppd->connection_status = e_source_get_connection_status (ppd->auth_source);
+               ppd->remember_password = e_credentials_prompter_eval_remember_password (ppd->cred_source);
+               ppd->error_text = g_strdup (error_text);
+               ppd->credentials = e_named_parameters_new_clone (credentials);
+               ppd->allow_source_save = allow_source_save;
+               ppd->async_result = async_result ? g_object_ref (async_result) : NULL;
+
+               /* If the prompter doesn't auto-prompt, then it should not auto-close the prompt as well. */
+               if (e_credentials_prompter_get_auto_prompt (prompter)) {
+                       ppd->notify_handler_id = g_signal_connect (ppd->auth_source, 
"notify::connection-status",
+                               G_CALLBACK (credentials_prompter_connection_status_changed_cb), 
prompter_impl);
+               } else {
+                       ppd->notify_handler_id = 0;
+               }
+
+               prompter->priv->queue = g_slist_append (prompter->priv->queue, ppd);
+
+               credentials_prompter_schedule_process_next_prompt (prompter);
+       }
+
+       g_rec_mutex_unlock (&prompter->priv->queue_lock);
+
+       if (!success && async_result) {
+               e_credentials_prompter_complete_prompt_call (prompter, async_result, auth_source, NULL, NULL);
+       }
+}
+
+static void
+credentials_prompter_store_credentials_cb (GObject *source_object,
+                                          GAsyncResult *result,
+                                          gpointer user_data)
+{
+       GError *error = NULL;
+
+       if (!e_source_credentials_provider_store_finish (E_SOURCE_CREDENTIALS_PROVIDER (source_object), 
result, &error) &&
+           !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_warning ("%s: Failed to store source credentials: %s", G_STRFUNC, error ? error->message : 
"Unknown error");
+       }
+
+       g_clear_error (&error);
+}
+
+static void
+credentials_prompter_source_write_cb (GObject *source_object,
+                                     GAsyncResult *result,
+                                     gpointer user_data)
+{
+       GError *error = NULL;
+
+       if (!e_source_write_finish (E_SOURCE (source_object), result, &error) &&
+           !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+               g_warning ("%s: Failed to write source changes: %s", G_STRFUNC, error ? error->message : 
"Unknown error");
+       }
+
+       g_clear_error (&error);
+}
+
+static void
+e_credentials_prompter_prompt_finish_for_source (ECredentialsPrompter *prompter,
+                                                ProcessPromptData *ppd,
+                                                const ENamedParameters *credentials)
+{
+       gboolean changed = FALSE;
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+       g_return_if_fail (ppd != NULL);
+
+       if (!credentials)
+               return;
+
+       if (e_source_has_extension (ppd->cred_source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
+               ESourceAuthentication *auth_extension = e_source_get_extension (ppd->cred_source, 
E_SOURCE_EXTENSION_AUTHENTICATION);
+
+               if (e_source_credentials_provider_can_store (e_credentials_prompter_get_provider (prompter), 
ppd->cred_source)) {
+                       e_source_credentials_provider_store (e_credentials_prompter_get_provider (prompter), 
ppd->cred_source, credentials,
+                               e_source_authentication_get_remember_password (auth_extension),
+                               prompter->priv->cancellable,
+                               credentials_prompter_store_credentials_cb, NULL);
+               }
+
+               if (e_source_get_writable (ppd->cred_source)) {
+                       const gchar *username;
+
+                       username = e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME);
+                       if (username && *username &&
+                           g_strcmp0 (username, e_source_authentication_get_user (auth_extension)) != 0) {
+                               e_source_authentication_set_user (auth_extension, username);
+                               changed = TRUE;
+                       }
+               }
+       }
+
+       if (ppd->allow_source_save && e_source_get_writable (ppd->cred_source) &&
+           (changed || (ppd->remember_password ? 1 : 0) != (e_credentials_prompter_eval_remember_password 
(ppd->cred_source) ? 1 : 0))) {
+               e_source_write (ppd->cred_source, prompter->priv->cancellable,
+                       credentials_prompter_source_write_cb, NULL);
+       }
+
+       if (ppd->async_result) {
+               ECredentialsPrompter *prompter;
+
+               prompter = g_weak_ref_get (ppd->prompter);
+               if (prompter) {
+                       e_credentials_prompter_complete_prompt_call (prompter, ppd->async_result, 
ppd->auth_source, credentials, NULL);
+                       g_clear_object (&prompter);
+
+                       /* To not be completed multiple times */
+                       g_clear_object (&ppd->async_result);
+               }
+       } else {
+               e_source_invoke_authenticate (ppd->auth_source, credentials, prompter->priv->cancellable,
+                       credentials_prompter_invoke_authenticate_cb, NULL);
+       }
+}
+
+static void
+credentials_prompter_prompt_finished_cb (ECredentialsPrompterImpl *prompter_impl,
+                                        gpointer prompt_id,
+                                        const ENamedParameters *credentials,
+                                        ECredentialsPrompter *prompter)
+{
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl));
+       g_return_if_fail (prompt_id != NULL);
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       g_rec_mutex_lock (&prompter->priv->queue_lock);
+
+       if (prompt_id == prompter->priv->processing_prompt) {
+               ProcessPromptData *ppd = prompter->priv->processing_prompt;
+               GSList *link, *to_remove = NULL;
+
+               prompter->priv->processing_prompt = NULL;
+
+               e_credentials_prompter_prompt_finish_for_source (prompter, ppd, credentials);
+
+               /* Finish also any other pending prompts for the same credentials source
+                  as was finished this one. This can be relevant to collection sources. */
+               for (link = prompter->priv->queue; link; link = g_slist_next (link)) {
+                       ProcessPromptData *sub_ppd = link->data;
+
+                       if (sub_ppd && sub_ppd->cred_source && e_source_equal (sub_ppd->cred_source, 
ppd->cred_source)) {
+                               to_remove = g_slist_prepend (to_remove, sub_ppd);
+                       }
+               }
+
+               for (link = to_remove; link; link = g_slist_next (link)) {
+                       ProcessPromptData *sub_ppd = link->data;
+
+                       if (sub_ppd) {
+                               prompter->priv->queue = g_slist_remove (prompter->priv->queue, sub_ppd);
+                               e_credentials_prompter_prompt_finish_for_source (prompter, sub_ppd, 
credentials);
+                       }
+               }
+
+               g_slist_free_full (to_remove, process_prompt_data_free);
+               process_prompt_data_free (ppd);
+
+               credentials_prompter_schedule_process_next_prompt (prompter);
+       } else {
+               g_warning ("%s: Unknown prompt_id %p", G_STRFUNC, prompt_id);
+       }
+
+       g_rec_mutex_unlock (&prompter->priv->queue_lock);
+}
+
+static gboolean
+credentials_prompter_prompt_with_source_details (ECredentialsPrompter *prompter,
+                                                LookupSourceDetailsData *data,
+                                                const gchar *error_text,
+                                                ECredentialsPrompterPromptFlags flags,
+                                                GSimpleAsyncResult *async_result)
+{
+       ECredentialsPrompterImpl *prompter_impl = NULL;
+       gchar *method = NULL;
+       gboolean success = TRUE;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), FALSE);
+       g_return_val_if_fail (data != NULL, FALSE);
+
+       if (e_source_has_extension (data->cred_source, E_SOURCE_EXTENSION_AUTHENTICATION)) {
+               ESourceAuthentication *authentication = e_source_get_extension (data->cred_source, 
E_SOURCE_EXTENSION_AUTHENTICATION);
+
+               method = e_source_authentication_dup_method (authentication);
+       }
+
+       g_mutex_lock (&prompter->priv->prompters_lock);
+
+       prompter_impl = g_hash_table_lookup (prompter->priv->prompters, method ? method : "");
+       if (!prompter_impl && method && *method)
+               prompter_impl = g_hash_table_lookup (prompter->priv->prompters, "");
+
+       if (prompter_impl)
+               g_object_ref (prompter_impl);
+
+       g_mutex_unlock (&prompter->priv->prompters_lock);
+
+       if (prompter_impl) {
+               ENamedParameters *credentials;
+
+               credentials = e_named_parameters_new ();
+               if (data->credentials)
+                       e_named_parameters_assign (credentials, data->credentials);
+
+               if (async_result && data->credentials && (flags & 
E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_STORED_CREDENTIALS) != 0) {
+                       e_credentials_prompter_complete_prompt_call (prompter, async_result, 
data->auth_source, credentials, NULL);
+               } else if (!e_source_credentials_provider_can_prompt (prompter->priv->provider, 
data->auth_source)) {
+                       /* This source cannot be asked for credentials, thus end with a 'not supported' 
error. */
+                       GError *error;
+
+                       error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                               _("Source '%s' doesn't support prompt for credentials"),
+                               e_source_get_display_name (data->cred_source));
+
+                       if (async_result)
+                               e_credentials_prompter_complete_prompt_call (prompter, async_result, 
data->auth_source, NULL, error);
+
+                       g_clear_error (&error);
+               } else {
+                       e_credentials_prompter_manage_impl_prompt (prompter, prompter_impl,
+                               data->auth_source, data->cred_source, error_text, credentials,
+                               !async_result || (flags & 
E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_SOURCE_SAVE) != 0,
+                               async_result);
+               }
+
+               e_named_parameters_free (credentials);
+       } else {
+               /* Shoud not happen, because the password prompter is added as the default prompter. */
+               g_warning ("%s: No prompter impl found for an authentication method '%s'", G_STRFUNC, method 
? method : "");
+               success = FALSE;
+       }
+
+       g_clear_object (&prompter_impl);
+       g_free (method);
+
+       return success;
+}
+
+static void
+credentials_prompter_lookup_source_details_before_prompt_cb (GObject *source_object,
+                                                            GAsyncResult *result,
+                                                            gpointer user_data)
+{
+       CredentialsPromptData *prompt_data = user_data;
+       ECredentialsPrompter *prompter = NULL;
+       LookupSourceDetailsData *data = NULL;
+       GError *error = NULL;
+
+       g_return_if_fail (prompt_data != NULL);
+       g_return_if_fail (E_IS_SOURCE (source_object));
+
+       if (!credentials_prompter_lookup_source_details_finish (E_SOURCE (source_object), result, &prompter, 
&data, &error)) {
+               g_clear_error (&error);
+               credentials_prompt_data_free (prompt_data);
+               return;
+       }
+
+       if (credentials_prompter_prompt_with_source_details (prompter, data, prompt_data->error_text,
+               prompt_data->flags, prompt_data->async_result)) {
+               /* To not finish the async_result multiple times */
+               g_clear_object (&prompt_data->async_result);
+       }
+
+       g_clear_object (&prompter);
+
+       credentials_prompt_data_free (prompt_data);
+       lookup_source_details_data_free (data);
+}
+
+static void
+credentials_prompter_lookup_source_details_cb (GObject *source_object,
+                                              GAsyncResult *result,
+                                              gpointer user_data)
+{
+       LookupSourceDetailsData *data = NULL;
+       ECredentialsPrompter *prompter = NULL;
+       ESource *source;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_SOURCE (source_object));
+
+       source = E_SOURCE (source_object);
+
+       if (!credentials_prompter_lookup_source_details_finish (source, result, &prompter, &data, &error)) {
+               g_clear_error (&error);
+               return;
+       }
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+       g_return_if_fail (data != NULL);
+
+       if (data->credentials) {
+               e_source_invoke_authenticate (E_SOURCE (data->auth_source), data->credentials, 
prompter->priv->cancellable, credentials_prompter_invoke_authenticate_cb, NULL);
+       } else {
+               credentials_prompter_prompt_with_source_details (prompter, data, NULL, 0, NULL);
+       }
+
+       lookup_source_details_data_free (data);
+       g_clear_object (&prompter);
+}
+
+static void
+credentials_prompter_credentials_required_cb (ESourceRegistry *registry,
+                                             ESource *source,
+                                             ESourceCredentialsReason reason,
+                                             const gchar *certificate_pem,
+                                             GTlsCertificateFlags certificate_errors,
+                                             const GError *op_error,
+                                             ECredentialsPrompter *prompter)
+{
+       g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       /* Only these two reasons are meant to be used to prompt the user for credentials. */
+       if (reason != E_SOURCE_CREDENTIALS_REASON_REQUIRED &&
+           reason != E_SOURCE_CREDENTIALS_REASON_REJECTED)
+               return;
+
+       /* Global auto-prompt or the source's auto-prompt is disabled. */
+       if (!e_credentials_prompter_get_auto_prompt (prompter) ||
+           e_credentials_prompter_get_auto_prompt_disabled_for (prompter, source))
+               return;
+
+       /* This is a re-prompt, but the source cannot be prompted for credentials. */
+       if (reason == E_SOURCE_CREDENTIALS_REASON_REJECTED &&
+           !e_source_credentials_provider_can_prompt (prompter->priv->provider, source)) {
+               return;
+       }
+
+       if (reason == E_SOURCE_CREDENTIALS_REASON_REQUIRED) {
+               credentials_prompter_lookup_source_details (source, prompter,
+                       credentials_prompter_lookup_source_details_cb, NULL);
+               return;
+       }
+
+       e_credentials_prompter_prompt (prompter, source, op_error ? op_error->message : NULL, 0, NULL, NULL);
+}
+
+static gboolean
+credentials_prompter_get_dialog_parent_accumulator (GSignalInvocationHint *ihint,
+                                                   GValue *return_accu,
+                                                   const GValue *handler_return,
+                                                   gpointer data)
+{
+       if (handler_return && g_value_get_object (handler_return) != NULL) {
+               g_value_set_object (return_accu, g_value_get_object (handler_return));
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void
+credentials_prompter_set_registry (ECredentialsPrompter *prompter,
+                                  ESourceRegistry *registry)
+{
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+       g_return_if_fail (E_IS_SOURCE_REGISTRY (registry));
+       g_return_if_fail (prompter->priv->registry == NULL);
+
+       prompter->priv->registry = g_object_ref (registry);
+       prompter->priv->provider = e_source_credentials_provider_new (prompter->priv->registry);
+
+       g_signal_connect (prompter->priv->registry, "credentials-required",
+               G_CALLBACK (credentials_prompter_credentials_required_cb), prompter);
+}
+
+static void
+credentials_prompter_set_property (GObject *object,
+                                  guint property_id,
+                                  const GValue *value,
+                                  GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_REGISTRY:
+                       credentials_prompter_set_registry (
+                               E_CREDENTIALS_PROMPTER (object),
+                               g_value_get_object (value));
+                       return;
+
+               case PROP_AUTO_PROMPT:
+                       e_credentials_prompter_set_auto_prompt (
+                               E_CREDENTIALS_PROMPTER (object),
+                               g_value_get_boolean (value));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+credentials_prompter_get_property (GObject *object,
+                                  guint property_id,
+                                  GValue *value,
+                                  GParamSpec *pspec)
+{
+       switch (property_id) {
+               case PROP_REGISTRY:
+                       g_value_set_object (value,
+                               e_credentials_prompter_get_registry (
+                               E_CREDENTIALS_PROMPTER (object)));
+                       return;
+
+               case PROP_PROVIDER:
+                       g_value_set_object (value,
+                               e_credentials_prompter_get_provider (
+                               E_CREDENTIALS_PROMPTER (object)));
+                       return;
+
+               case PROP_AUTO_PROMPT:
+                       g_value_set_boolean (value,
+                               e_credentials_prompter_get_auto_prompt (
+                               E_CREDENTIALS_PROMPTER (object)));
+                       return;
+       }
+
+       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+credentials_prompter_constructed (GObject *object)
+{
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_credentials_prompter_parent_class)->constructed (object);
+
+       e_extensible_load_extensions (E_EXTENSIBLE (object));
+}
+
+static void
+credentials_prompter_dispose (GObject *object)
+{
+       ECredentialsPrompter *prompter = E_CREDENTIALS_PROMPTER (object);
+       GHashTableIter iter;
+       gpointer key, value;
+
+       if (prompter->priv->cancellable) {
+               g_cancellable_cancel (prompter->priv->cancellable);
+               g_clear_object (&prompter->priv->cancellable);
+       }
+
+       if (prompter->priv->registry) {
+               g_signal_handlers_disconnect_by_data (prompter->priv->registry, prompter);
+               g_clear_object (&prompter->priv->registry);
+       }
+
+       g_rec_mutex_lock (&prompter->priv->queue_lock);
+
+       if (prompter->priv->schedule_idle_id) {
+               g_source_remove (prompter->priv->schedule_idle_id);
+               prompter->priv->schedule_idle_id = 0;
+       }
+
+       g_rec_mutex_unlock (&prompter->priv->queue_lock);
+
+       g_clear_object (&prompter->priv->provider);
+
+       g_mutex_lock (&prompter->priv->prompters_lock);
+
+       g_hash_table_iter_init (&iter, prompter->priv->prompters);
+       while (g_hash_table_iter_next (&iter, &key, &value)) {
+               ECredentialsPrompterImpl *prompter_impl = key;
+
+               g_signal_handlers_disconnect_by_func (prompter_impl, credentials_prompter_prompt_finished_cb, 
prompter);
+       }
+
+       g_hash_table_remove_all (prompter->priv->prompters);
+       g_hash_table_remove_all (prompter->priv->known_prompters);
+       g_mutex_unlock (&prompter->priv->prompters_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_credentials_prompter_parent_class)->dispose (object);
+}
+
+static void
+credentials_prompter_finalize (GObject *object)
+{
+       ECredentialsPrompter *prompter = E_CREDENTIALS_PROMPTER (object);
+
+       g_hash_table_destroy (prompter->priv->prompters);
+       g_hash_table_destroy (prompter->priv->known_prompters);
+       g_mutex_clear (&prompter->priv->prompters_lock);
+
+       g_hash_table_destroy (prompter->priv->disabled_auto_prompt);
+       g_mutex_clear (&prompter->priv->disabled_auto_prompt_lock);
+
+       g_rec_mutex_clear (&prompter->priv->queue_lock);
+
+       /* Chain up to parent's method. */
+       G_OBJECT_CLASS (e_credentials_prompter_parent_class)->finalize (object);
+}
+
+static void
+e_credentials_prompter_class_init (ECredentialsPrompterClass *class)
+{
+       GObjectClass *object_class;
+
+       g_type_class_add_private (class, sizeof (ECredentialsPrompterPrivate));
+
+       object_class = G_OBJECT_CLASS (class);
+       object_class->set_property = credentials_prompter_set_property;
+       object_class->get_property = credentials_prompter_get_property;
+       object_class->constructed = credentials_prompter_constructed;
+       object_class->dispose = credentials_prompter_dispose;
+       object_class->finalize = credentials_prompter_finalize;
+
+       /**
+        * ECredentialsPrompter:auto-prompt:
+        *
+        * Whether the #ECredentialsPrompter can response to credential
+        * requests automatically.
+        *
+        * Since: 3.14
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_AUTO_PROMPT,
+               g_param_spec_boolean (
+                       "auto-prompt",
+                       "Auto Prompt",
+                       "Whether can response to credential requests automatically",
+                       TRUE,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+
+       /**
+        * ECredentialsPrompter:registry:
+        *
+        * The #ESourceRegistry object, to whose credential requests the prompter listens.
+        *
+        * Since: 3.14
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_REGISTRY,
+               g_param_spec_object (
+                       "registry",
+                       "Registry",
+                       "An ESourceRegistry",
+                       E_TYPE_SOURCE_REGISTRY,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT_ONLY |
+                       G_PARAM_STATIC_STRINGS));
+
+       /**
+        * ECredentialsPrompter:provider:
+        *
+        * The #ESourceCredentialsProvider object, which the prompter uses.
+        *
+        * Since: 3.14
+        **/
+       g_object_class_install_property (
+               object_class,
+               PROP_PROVIDER,
+               g_param_spec_object (
+                       "provider",
+                       "Provider",
+                       "An ESourceCredentialsProvider",
+                       E_TYPE_SOURCE_CREDENTIALS_PROVIDER,
+                       G_PARAM_READABLE |
+                       G_PARAM_STATIC_STRINGS));
+
+       /**
+        * ECredentialsPrompter::get-dialog-parent:
+        * @prompter: the #ECredentialsPrompter which emitted the signal
+        *
+        * Emitted when a new dialog will be shown, to get the right parent
+        * window for it. If the result of the call is %NULL, then it tries
+        * to get the window from the default GtkApplication.
+        *
+        * Since: 3.14
+        **/
+       signals[GET_DIALOG_PARENT] = g_signal_new (
+               "get-dialog-parent",
+               G_OBJECT_CLASS_TYPE (object_class),
+               G_SIGNAL_RUN_LAST,
+               G_STRUCT_OFFSET (ECredentialsPrompterClass, get_dialog_parent),
+               credentials_prompter_get_dialog_parent_accumulator, NULL, NULL,
+               GTK_TYPE_WINDOW, 0, G_TYPE_NONE);
+
+       /* Ensure built-in credential providers implementation types */
+       g_type_ensure (E_TYPE_CREDENTIALS_PROMPTER_IMPL_PASSWORD);
+}
+
+static void
+e_credentials_prompter_init (ECredentialsPrompter *prompter)
+{
+       prompter->priv = G_TYPE_INSTANCE_GET_PRIVATE (prompter, E_TYPE_CREDENTIALS_PROMPTER, 
ECredentialsPrompterPrivate);
+
+       prompter->priv->auto_prompt = TRUE;
+       prompter->priv->provider = NULL;
+       prompter->priv->cancellable = g_cancellable_new ();
+
+       g_mutex_init (&prompter->priv->prompters_lock);
+       prompter->priv->prompters = g_hash_table_new_full (camel_strcase_hash, camel_strcase_equal, g_free, 
g_object_unref);
+       prompter->priv->known_prompters = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+       g_mutex_init (&prompter->priv->disabled_auto_prompt_lock);
+       prompter->priv->disabled_auto_prompt = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+       g_rec_mutex_init (&prompter->priv->queue_lock);
+}
+
+/**
+ * e_credentials_prompter_new:
+ * @registry: an #ESourceRegistry to have the prompter listen to
+ *
+ * Creates a new #ECredentialsPrompter, which listens for credential requests
+ * from @registry.
+ *
+ * Returns: (transfer full): a new #ECredentialsPrompter
+ *
+ * Since: 3.14
+ **/
+ECredentialsPrompter *
+e_credentials_prompter_new (ESourceRegistry *registry)
+{
+       return g_object_new (E_TYPE_CREDENTIALS_PROMPTER,
+               "registry", registry,
+               NULL);
+}
+
+/**
+ * e_credentials_prompter_get_registry:
+ * @prompter: an #ECredentialsPrompter
+ *
+ * Returns an #ESourceRegistry, to which the @prompter listens.
+ *
+ * Returns: (transfer none): an #ESourceRegistry, to which the @prompter listens.
+ *
+ * Since: 3.14
+ **/
+ESourceRegistry *
+e_credentials_prompter_get_registry (ECredentialsPrompter *prompter)
+{
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), NULL);
+
+       return prompter->priv->registry;
+}
+
+/**
+ * e_credentials_prompter_get_provider:
+ * @prompter: an #ECredentialsPrompter
+ *
+ * Returns an #ESourceCredentialsProvider, which the @prompter uses.
+ *
+ * Returns: (transfer none): an #ESourceCredentialsProvider, which the @prompter uses.
+ *
+ * Since: 3.14
+ **/
+ESourceCredentialsProvider *
+e_credentials_prompter_get_provider (ECredentialsPrompter *prompter)
+{
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), NULL);
+       g_return_val_if_fail (prompter->priv->provider != NULL, NULL);
+
+       return prompter->priv->provider;
+}
+
+/**
+ * e_credentials_prompter_get_auto_prompt:
+ * @prompter: an #ECredentialsPrompter
+ *
+ * Returns, whether can respond to credential prompts automatically.
+ * Default value is %TRUE.
+ *
+ * This property does not influence direct calls of e_credentials_prompter_prompt().
+ *
+ * Returns: Whether can respond to credential prompts automatically.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_credentials_prompter_get_auto_prompt (ECredentialsPrompter *prompter)
+{
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), FALSE);
+
+       return prompter->priv->auto_prompt;
+}
+
+/**
+ * e_credentials_prompter_set_auto_prompt:
+ * @prompter: an #ECredentialsPrompter
+ * @auto_prompt: new value of the auto-prompt property
+ *
+ * Sets whether can respond to credential prompts automatically. That means that
+ * whenever any ESource will ask for credentials, it'll try to provide them.
+ *
+ * Use e_credentials_prompter_set_auto_prompt_disabled_for() to influence
+ * auto-prompt per an #ESource.
+ *
+ * This property does not influence direct calls of e_credentials_prompter_prompt().
+ *
+ * Since: 3.14
+ **/
+void
+e_credentials_prompter_set_auto_prompt (ECredentialsPrompter *prompter,
+                                       gboolean auto_prompt)
+{
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       if ((prompter->priv->auto_prompt ? 1 : 0) == (auto_prompt ? 1 : 0))
+               return;
+
+       prompter->priv->auto_prompt = auto_prompt;
+
+       g_object_notify (G_OBJECT (prompter), "auto-prompt");
+}
+
+/**
+ * @prompter: an #ECredentialsPrompter
+ * @source: an #ESource
+ * @is_disabled: whether the auto-prompt should be disabled for this @source
+ *
+ * Sets whether the auto-prompt should be disabled for the given @source.
+ * All sources can be auto-prompted by default. This is a complementary
+ * value for the ECredentialsPrompter::auto-prompt property.
+ *
+ * This value does not influence direct calls of e_credentials_prompter_prompt().
+ *
+ * Since: 3.14
+ **/
+void
+e_credentials_prompter_set_auto_prompt_disabled_for (ECredentialsPrompter *prompter,
+                                                    ESource *source,
+                                                    gboolean is_disabled)
+{
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (e_source_get_uid (source) != NULL);
+
+       g_mutex_lock (&prompter->priv->disabled_auto_prompt_lock);
+
+       if (is_disabled)
+               g_hash_table_insert (prompter->priv->disabled_auto_prompt, g_strdup (e_source_get_uid 
(source)), GINT_TO_POINTER (1));
+       else
+               g_hash_table_remove (prompter->priv->disabled_auto_prompt, e_source_get_uid (source));
+
+       g_mutex_unlock (&prompter->priv->disabled_auto_prompt_lock);
+}
+
+/**
+ * @prompter: an #ECredentialsPrompter
+ * @source: an #ESource
+ *
+ * Returns whether the auto-prompt is disabled for the given @source.
+ * All sources can be auto-prompted by default. This is a complementary
+ * value for the ECredentialsPrompter::auto-prompt property.
+ *
+ * This value does not influence direct calls of e_credentials_prompter_prompt().
+ *
+ * Returns: Whether the auto-prompt is disabled for the given @source
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_credentials_prompter_get_auto_prompt_disabled_for (ECredentialsPrompter *prompter,
+                                                    ESource *source)
+{
+       gboolean is_disabled;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), TRUE);
+       g_return_val_if_fail (E_IS_SOURCE (source), TRUE);
+       g_return_val_if_fail (e_source_get_uid (source) != NULL, TRUE);
+
+       g_mutex_lock (&prompter->priv->disabled_auto_prompt_lock);
+
+       is_disabled = g_hash_table_contains (prompter->priv->disabled_auto_prompt, e_source_get_uid (source));
+
+       g_mutex_unlock (&prompter->priv->disabled_auto_prompt_lock);
+
+       return is_disabled;
+}
+
+static GtkWindow *
+credentials_prompter_guess_dialog_parent (ECredentialsPrompter *prompter)
+{
+       GApplication *app;
+
+       app = g_application_get_default ();
+       if (!app)
+               return NULL;
+
+       if (GTK_IS_APPLICATION (app))
+               return gtk_application_get_active_window (GTK_APPLICATION (app));
+
+       return NULL;
+}
+
+/**
+ * e_credentials_prompter_get_dialog_parent:
+ * @prompter: an #ECredentialsPrompter
+ *
+ * Returns a #GtkWindow, which should be used as a dialog parent. This is determined
+ * by an ECredentialsPrompter::get-dialog-parent signal emission. If there is no callback
+ * registered or the current callbacks don't have any suitable window, then there's
+ * chosen the last active window from the default GApplication, if any available.
+ *
+ * Returns: (transfer none): a #GtkWindow, to be used as a dialog parent, or %NULL.
+ *
+ * Since: 3.14
+ **/
+GtkWindow *
+e_credentials_prompter_get_dialog_parent (ECredentialsPrompter *prompter)
+{
+       GtkWindow *parent = NULL;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), NULL);
+
+       g_signal_emit (prompter, signals[GET_DIALOG_PARENT], 0, &parent);
+
+       if (!parent)
+               parent = credentials_prompter_guess_dialog_parent (prompter);
+
+       return parent;
+}
+
+/**
+ * e_credentials_prompter_register_impl:
+ * @prompter: an #ECredentialsPrompter
+ * @authentication_method: (allow none): an authentication method to registr @prompter_impl for; or %NULL
+ * @prompter_impl: an #ECredentialsPrompterImpl
+ *
+ * Registers a prompter implementation for a given authentication method. If there is
+ * registered a prompter for the same @authentication_method, then the function does
+ * nothing, otherwise it adds its own reference on the @prompter_impl, and uses it
+ * for that authentication method. One @prompter_impl can be registered for multiple
+ * authentication methods.
+ *
+ * A special value %NULL can be used for the @authentication_method, which means
+ * a default credentials prompter, that is to be used when there is no prompter
+ * registered for the exact authentication method.
+ *
+ * Returns: %TRUE on success, %FALSE on failure or when there was another prompter
+ * implementation registered for the given authentication method.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_credentials_prompter_register_impl (ECredentialsPrompter *prompter,
+                                     const gchar *authentication_method,
+                                     ECredentialsPrompterImpl *prompter_impl)
+{
+       guint known_prompters;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), FALSE);
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER_IMPL (prompter_impl), FALSE);
+
+       if (!authentication_method)
+               authentication_method = "";
+
+       g_mutex_lock (&prompter->priv->prompters_lock);
+
+       if (g_hash_table_lookup (prompter->priv->prompters, authentication_method) != NULL) {
+               g_mutex_unlock (&prompter->priv->prompters_lock);
+               return FALSE;
+       }
+
+       g_hash_table_insert (prompter->priv->prompters, g_strdup (authentication_method), g_object_ref 
(prompter_impl));
+
+       known_prompters = GPOINTER_TO_UINT (g_hash_table_lookup (prompter->priv->known_prompters, 
prompter_impl));
+       if (!known_prompters) {
+               g_signal_connect (prompter_impl, "prompt-finished", G_CALLBACK 
(credentials_prompter_prompt_finished_cb), prompter);
+       }
+       g_hash_table_insert (prompter->priv->known_prompters, prompter_impl, GUINT_TO_POINTER 
(known_prompters + 1));
+
+       g_mutex_unlock (&prompter->priv->prompters_lock);
+
+       return TRUE;
+}
+
+/**
+ * e_credentials_prompter_unregister_impl:
+ * @prompter: an #ECredentialsPrompter
+ * @authentication_method: (allow none): an authentication method to registr @prompter_impl for; or %NULL
+ * @prompter_impl: an #ECredentialsPrompterImpl
+ *
+ * Unregisters previously registered @prompter_impl for the given @autnetication_method with
+ * e_credentials_prompter_register_impl(). Function does nothing, if no such authentication
+ * method is registered or if it has set a different prompter implementation.
+ *
+ * Since: 3.14
+ **/
+void
+e_credentials_prompter_unregister_impl (ECredentialsPrompter *prompter,
+                                       const gchar *authentication_method,
+                                       ECredentialsPrompterImpl *prompter_impl)
+{
+       ECredentialsPrompterImpl *current_prompter_impl;
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       if (!authentication_method)
+               authentication_method = "";
+
+       g_mutex_lock (&prompter->priv->prompters_lock);
+
+       current_prompter_impl = g_hash_table_lookup (prompter->priv->prompters, authentication_method);
+       if (current_prompter_impl == prompter_impl) {
+               guint known_prompters;
+
+               known_prompters = GPOINTER_TO_UINT (g_hash_table_lookup (prompter->priv->known_prompters, 
prompter_impl));
+               if (known_prompters == 1) {
+                       g_signal_handlers_disconnect_by_func (prompter_impl, 
credentials_prompter_prompt_finished_cb, prompter);
+                       g_hash_table_remove (prompter->priv->known_prompters, prompter_impl);
+               } else {
+                       known_prompters--;
+                       g_hash_table_insert (prompter->priv->known_prompters, prompter_impl, GUINT_TO_POINTER 
(known_prompters + 1));
+               }
+
+               g_hash_table_remove (prompter->priv->prompters, authentication_method);
+       }
+
+       g_mutex_unlock (&prompter->priv->prompters_lock);
+}
+
+static void
+credentials_prompter_get_last_credentials_required_arguments_cb (GObject *source_object,
+                                                                GAsyncResult *result,
+                                                                gpointer user_data)
+{
+       ECredentialsPrompter *prompter = user_data;
+       ESource *source;
+       ESourceCredentialsReason reason = E_SOURCE_CREDENTIALS_REASON_UNKNOWN;
+       gchar *certificate_pem = NULL;
+       GTlsCertificateFlags certificate_errors = 0;
+       GError *op_error = NULL;
+       GError *error = NULL;
+
+       g_return_if_fail (E_IS_SOURCE (source_object));
+
+       source = E_SOURCE (source_object);
+
+       if (!e_source_get_last_credentials_required_arguments_finish (source, result,
+               &reason, &certificate_pem, &certificate_errors, &op_error, &error)) {
+               if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+                       g_warning ("%s: Failed to get last credential values: %s", G_STRFUNC, error ? 
error->message : "Unknown error");
+               }
+
+               g_clear_error (&error);
+               return;
+       }
+
+       /* Can check only now, when know the operation was not cancelled and the prompter freed. */
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       /* Check once again, as this was called asynchronously and anything could change meanwhile. */
+       if (e_source_get_connection_status (source) == E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS) {
+               credentials_prompter_credentials_required_cb (prompter->priv->registry,
+                       source, reason, certificate_pem, certificate_errors, op_error, prompter);
+       }
+
+       g_free (certificate_pem);
+       g_clear_error (&op_error);
+}
+
+/**
+ * e_credentials_prompter_process_awaiting_credentials:
+ * @prompter: an #ECredentialsPrompter
+ *
+ * Process all enabled sources with connection state #E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS,
+ * like if they just asked for its credentials for the first time.
+ *
+ * Since: 3.14
+ **/
+void
+e_credentials_prompter_process_awaiting_credentials (ECredentialsPrompter *prompter)
+{
+       GList *sources, *link;
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+
+       sources = e_source_registry_list_enabled (prompter->priv->registry, NULL);
+       for (link = sources; link; link = g_list_next (link)) {
+               ESource *source = link->data;
+
+               if (!source)
+                       continue;
+
+               if (e_source_get_connection_status (source) == 
E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS) {
+                       /* Check what failed the last time */
+                       e_credentials_prompter_process_source (prompter, source);
+               }
+       }
+
+       g_list_free_full (sources, g_object_unref);
+}
+
+/**
+ * e_credentials_prompter_process_source:
+ * @prompter: an #ECredentialsPrompter
+ * @source: an #ESource
+ *
+ * Continues a credential prompt for @source. Returns, whether anything wil be done.
+ * The %FALSE either means that the @source<!-- -->'s connection status is not
+ * the %E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS.
+ *
+ * Returns: Whether continues with the credentials prompt.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_credentials_prompter_process_source (ECredentialsPrompter *prompter,
+                                      ESource *source)
+{
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       if (e_source_get_connection_status (source) != E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS)
+               return FALSE;
+
+       e_source_get_last_credentials_required_arguments (source, prompter->priv->cancellable,
+               credentials_prompter_get_last_credentials_required_arguments_cb, prompter);
+
+       return TRUE;
+}
+
+/**
+ * e_credentials_prompter_prompt:
+ * @prompter: an #ECredentialsPrompter
+ * @source: an #ESource, which prompt the credentials for
+ * @error_text: (allow none): Additional error text to show to a user, or %NULL
+ * @flags: a bit-or of #ECredentialsPrompterPromptFlags
+ * @callback: (allow none): a callback to call when the credentials are ready, or %NULL
+ * @user_data: user data passed into @callback
+ *
+ * Asks the @prompter to prompt for credentials, which are returned
+ * to the caller through @callback, when available.The @flags are ignored,
+ * when the @callback is %NULL; the credentials are passed to the @source
+ * with e_source_invoke_authenticate() directly, in this case.
+ * Call e_credentials_prompter_prompt_finish() in @callback to get to
+ * the provided credentials.
+ *
+ * Since: 3.14
+ **/
+void
+e_credentials_prompter_prompt (ECredentialsPrompter *prompter,
+                              ESource *source,
+                              const gchar *error_text,
+                              ECredentialsPrompterPromptFlags flags,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+       CredentialsPromptData *prompt_data;
+
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       prompt_data = g_new0 (CredentialsPromptData, 1);
+       prompt_data->source = g_object_ref (source);
+       prompt_data->error_text = g_strdup (error_text);
+       prompt_data->flags = flags;
+       prompt_data->async_result = callback ? g_simple_async_result_new (G_OBJECT (prompter),
+               callback, user_data, e_credentials_prompter_prompt) : NULL;
+
+       /* Just it can be shown in the UI as a prefilled value and the right source (collection) is used. */
+       credentials_prompter_lookup_source_details (source, prompter,
+               credentials_prompter_lookup_source_details_before_prompt_cb, prompt_data);
+}
+
+/**
+ * e_credentials_prompter_prompt_finish:
+ * @prompter: an #ECredentialsPrompter
+ * @result: a #GAsyncResult
+ * @out_source: (transfer full): (allow none): optionally set to an #ESource, on which the prompt was 
started; can be %NULL
+ * @out_credentials: (transfer full): set to an #ENamedParameters with provied credentials
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes a credentials prompt previously started with e_credentials_prompter_prompt().
+ * The @out_source will have set a referenced #ESource, for which the prompt
+ * was started. Unref it, when  no longer needed. Similarly the @out_credentials
+ * will have set a newly allocated #ENamedParameters structure with provided credentials,
+ * which should be freed with e_named_credentials_free() when no longer needed.
+ * Both output arguments will be set to %NULL on error and %FALSE will be returned.
+ *
+ * Returns: %TRUE on success, %FALSE otherwise.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_credentials_prompter_prompt_finish (ECredentialsPrompter *prompter,
+                                     GAsyncResult *result,
+                                     ESource **out_source,
+                                     ENamedParameters **out_credentials,
+                                     GError **error)
+{
+       CredentialsResultData *data;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), FALSE);
+       g_return_val_if_fail (g_simple_async_result_get_source_tag (G_SIMPLE_ASYNC_RESULT (result))
+               == e_credentials_prompter_prompt, FALSE);
+       g_return_val_if_fail (out_credentials, FALSE);
+
+       if (out_source)
+               *out_source = NULL;
+       *out_credentials = NULL;
+
+       if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+               return FALSE;
+
+       data = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
+       g_return_val_if_fail (data != NULL, FALSE);
+
+       if (data->credentials) {
+               if (out_source)
+                       *out_source = g_object_ref (data->source);
+               *out_credentials = e_named_parameters_new_clone (data->credentials);
+       } else {
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, _("Credentials prompt was 
cancelled"));
+
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+/**
+ * e_credentials_prompter_complete_prompt_call:
+ * @prompter: an #ECredentialsPrompter
+ * @async_result: a #GSimpleAsyncResult
+ * @source: an #ESource, on which the prompt was started
+ * @credentials: (allow none): credentials, as provided by a user, on %NULL, when the prompt was cancelled
+ * @error: (allow none): a resulting #GError, or %NULL
+ *
+ * Completes an ongoing credentials prompt on idle, by finishing the @async_result.
+ * This function is meant to be used by an #ECredentialsPrompterImpl implementation.
+ * To actually finish the credentials prompt previously started with
+ * e_credentials_prompter_prompt(), the e_credentials_prompter_prompt_finish() should
+ * be called from the provided callback.
+ *
+ * Using %NULL @credentials will result in a G_IO_ERROR_CANCELLED error, if
+ * no other @error is provided.
+ *
+ * Since: 3.14
+ **/
+void
+e_credentials_prompter_complete_prompt_call (ECredentialsPrompter *prompter,
+                                            GSimpleAsyncResult *async_result,
+                                            ESource *source,
+                                            const ENamedParameters *credentials,
+                                            const GError *error)
+{
+       g_return_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter));
+       g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (async_result));
+       g_return_if_fail (g_simple_async_result_get_source_tag (async_result) == 
e_credentials_prompter_prompt);
+       g_return_if_fail (source == NULL || E_IS_SOURCE (source));
+       if (credentials)
+               g_return_if_fail (E_IS_SOURCE (source));
+
+       if (error) {
+               g_simple_async_result_set_from_error (async_result, error);
+       } else if (!credentials) {
+               g_simple_async_result_set_error (async_result, G_IO_ERROR, G_IO_ERROR_CANCELLED, 
_("Credentials prompt was cancelled"));
+       } else {
+               CredentialsResultData *result;
+
+               result = g_new0 (CredentialsResultData, 1);
+               result->source = g_object_ref (source);
+               result->credentials = e_named_parameters_new_clone (credentials);
+
+               g_simple_async_result_set_op_res_gpointer (async_result, result, 
credentials_result_data_free);
+       }
+
+       g_simple_async_result_complete_in_idle (async_result);
+}
+
+static gboolean
+credentials_prompter_prompt_sync (ECredentialsPrompter *prompter,
+                                 ESource *source,
+                                 gboolean is_retry,
+                                 ECredentialsPrompterPromptFlags *flags,
+                                 const gchar *error_text,
+                                 ENamedParameters **out_credentials,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+       gboolean res = FALSE;
+       ESourceCredentialsProvider *credentials_provider;
+       ENamedParameters *credentials = NULL;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (flags != NULL, FALSE);
+       g_return_val_if_fail (out_credentials != NULL, FALSE);
+
+       if (g_cancellable_set_error_if_cancelled (cancellable, error))
+               return FALSE;
+
+       credentials_provider = e_credentials_prompter_get_provider (prompter);
+
+       if (!is_retry) {
+               ESource *cred_source;
+               GError *local_error = NULL;
+
+               cred_source = e_source_credentials_provider_ref_credentials_source (credentials_provider, 
source);
+
+               if (e_source_credentials_provider_lookup_sync (credentials_provider, cred_source ? 
cred_source : source,
+                       cancellable, &credentials, &local_error)) {
+                       res = TRUE;
+               } else if (!g_cancellable_is_cancelled (cancellable)) {
+                       /* To prompt for the password directly */
+                       is_retry = TRUE;
+                       g_clear_error (&local_error);
+               } else {
+                       g_propagate_error (error, local_error);
+               }
+
+               g_clear_object (&cred_source);
+       }
+
+       if (is_retry) {
+               EAsyncClosure *closure;
+               GAsyncResult *result;
+
+               *flags = (*flags) & (~E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_STORED_CREDENTIALS);
+
+               closure = e_async_closure_new ();
+
+               e_credentials_prompter_prompt (prompter, source, error_text, *flags,
+                       e_async_closure_callback, closure);
+
+               result = e_async_closure_wait (closure);
+
+               if (e_credentials_prompter_prompt_finish (prompter, result, NULL, &credentials, error)) {
+                       res = TRUE;
+               }
+
+               e_async_closure_free (closure);
+       }
+
+       if (res && credentials)
+               *out_credentials = e_named_parameters_new_clone (credentials);
+
+       e_named_parameters_free (credentials);
+
+       return res;
+}
+
+/**
+ * e_credentials_prompter_loop_prompt_sync:
+ * @prompter: an #ECredentialsPrompter
+ * @source: an #ESource to be prompted credentials for
+ * @flags: a bit-or of #ECredentialsPrompterPromptFlags initial flags
+ * @func: an #ECredentialsPrompterLoopPromptFunc user function to call to check provided credentials
+ * @user_data: user data to pass to @func
+ * @cancellable: (allow none): an optional #GCancellable, or %NULL
+ * @error: (allow none): a #GError, to store any errors to, or %NULL
+ *
+ * Runs a credentials prompt loop for @source, as long as the @func doesn't
+ * indicate that the provided credentials can be used to successfully
+ * authenticate against @source<!-- -->'s server, or that the @func
+ * returns %FALSE. The loop is also teminated when a used cancels
+ * the credentials prompt or the @cancellable is cancelled, though
+ * not sooner than the credentials prompt dialog is closed.
+ *
+ * Note: The function doesn't return until the loop is terminated, either
+ *    successfully or unsuccessfully. The function can be called from any
+ *    thread, though a dedicated thread is preferred.
+ *
+ * Returns: %TRUE, when the credentials were provided sucessfully and they
+ *   can be used to authenticate the @source; %FALSE otherwise.
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_credentials_prompter_loop_prompt_sync (ECredentialsPrompter *prompter,
+                                        ESource *source,
+                                        ECredentialsPrompterPromptFlags flags,
+                                        ECredentialsPrompterLoopPromptFunc func,
+                                        gpointer user_data,
+                                        GCancellable *cancellable,
+                                        GError **error)
+{
+       gboolean is_retry, authenticated;
+       ENamedParameters *credentials = NULL;
+
+       g_return_val_if_fail (E_IS_CREDENTIALS_PROMPTER (prompter), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (func != NULL, FALSE);
+
+       is_retry = FALSE;
+       authenticated = FALSE;
+
+       while (!authenticated && !g_cancellable_is_cancelled (cancellable)) {
+               GError *local_error = NULL;
+
+               e_named_parameters_free (credentials);
+               credentials = NULL;
+
+               if (!credentials_prompter_prompt_sync (prompter, source, is_retry, &flags, local_error ? 
local_error->message : NULL,
+                       &credentials, cancellable, error))
+                       break;
+
+               if (g_cancellable_set_error_if_cancelled (cancellable, error))
+                       break;
+
+               g_clear_error (&local_error);
+
+               if (!func (prompter, source, credentials, &authenticated, user_data, cancellable, 
&local_error)) {
+                       if (local_error)
+                               g_propagate_error (error, local_error);
+                       break;
+               }
+
+               is_retry = TRUE;
+       }
+
+       e_named_parameters_free (credentials);
+
+       return authenticated;
+}
diff --git a/libedataserverui/e-credentials-prompter.h b/libedataserverui/e-credentials-prompter.h
new file mode 100644
index 0000000..5fcbef9
--- /dev/null
+++ b/libedataserverui/e-credentials-prompter.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined (__LIBEDATASERVERUI_H_INSIDE__) && !defined (LIBEDATASERVERUI_COMPILATION)
+#error "Only <libedataserverui/libedataserverui.h> should be included directly."
+#endif
+
+#ifndef E_CREDENTIALS_PROMPTER_H
+#define E_CREDENTIALS_PROMPTER_H
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include <gtk/gtk.h>
+
+#include <libedataserver/libedataserver.h>
+
+#include <libedataserverui/e-credentials-prompter-impl.h>
+
+/* Standard GObject macros */
+#define E_TYPE_CREDENTIALS_PROMPTER \
+       (e_credentials_prompter_get_type ())
+#define E_CREDENTIALS_PROMPTER(obj) \
+       (G_TYPE_CHECK_INSTANCE_CAST \
+       ((obj), E_TYPE_CREDENTIALS_PROMPTER, ECredentialsPrompter))
+#define E_CREDENTIALS_PROMPTER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_CAST \
+       ((cls), E_TYPE_CREDENTIALS_PROMPTER, ECredentialsPrompterClass))
+#define E_IS_CREDENTIALS_PROMPTER(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_CREDENTIALS_PROMPTER))
+#define E_IS_CREDENTIALS_PROMPTER_CLASS(cls) \
+       (G_TYPE_CHECK_CLASS_TYPE \
+       ((cls), E_TYPE_CREDENTIALS_PROMPTER))
+#define E_CREDENTIALS_PROMPTER_GET_CLASS(obj) \
+       (G_TYPE_INSTANCE_GET_CLASS \
+       ((obj), E_TYPE_CREDENTIALS_PROMPTER, ECredentialsPrompterClass))
+
+G_BEGIN_DECLS
+
+typedef struct _ECredentialsPrompter ECredentialsPrompter;
+typedef struct _ECredentialsPrompterClass ECredentialsPrompterClass;
+typedef struct _ECredentialsPrompterPrivate ECredentialsPrompterPrivate;
+
+/**
+ * ECredentialsPrompterPromptFlags:
+ * @E_CREDENTIALS_PROMPTER_PROMPT_FLAG_NONE:
+ *   No flag is set.
+ * @E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_SOURCE_SAVE:
+ *   If set, any source changes during the credentials prompts, like
+ *   the "remember-password" or user name changes, will be automatically
+ *   stored in the source (written on the disk).
+ * @E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_STORED_CREDENTIALS:
+ *   If set, the stored credentials will be returned first. If there are no
+ *   credentials saved, then the user will be asked. Any credentials
+ *   reprompt should not have set this flag.
+ *
+ * An #ECredentialsPrompter prompt flags, influencing behaviour
+ * of the e_credentials_prompter_prompt().
+ *
+ * Since: 3.14
+ **/
+typedef enum {
+       E_CREDENTIALS_PROMPTER_PROMPT_FLAG_NONE                         = 0,
+       E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_SOURCE_SAVE            = 1 << 0,
+       E_CREDENTIALS_PROMPTER_PROMPT_FLAG_ALLOW_STORED_CREDENTIALS     = 1 << 1
+} ECredentialsPrompterPromptFlags;
+
+/**
+ * ECredentialsPrompterLoopPromptFunc:
+ * @prompter: an #ECredentialsPrompter
+ * @source: an #ESource, as passed to e_credentials_prompter_loop_prompt_sync()
+ * @credentials: an #ENamedParameters with provided credentials
+ * @out_authenticated: (out): set to %TRUE, when the authentication was successful
+ * @user_data: user data, as passed to e_credentials_prompter_loop_prompt_sync()
+ * @cancellable: a #GCancellable, as passed to e_credentials_prompter_loop_prompt_sync()
+ * @error: a #GError, to get an error, or %NULL
+ *
+ * Returns: %TRUE to continue the loop (reprompt credentials), unless @authenticated is
+ *   also set to %TRUE, or %FALSE on error, as an indication that the loop should
+ *   be terminated.
+ **/
+typedef gboolean (*ECredentialsPrompterLoopPromptFunc) (ECredentialsPrompter *prompter,
+                                                       ESource *source,
+                                                       const ENamedParameters *credentials,
+                                                       gboolean *out_authenticated,
+                                                       gpointer user_data,
+                                                       GCancellable *cancellable,
+                                                       GError **error);
+/**
+ * ECredentialsPrompter:
+ *
+ * Contains only private data that should be read and manipulated using the
+ * functions below.
+ *
+ * Since: 3.14
+ **/
+struct _ECredentialsPrompter {
+       GObject parent;
+       ECredentialsPrompterPrivate *priv;
+};
+
+struct _ECredentialsPrompterClass {
+       GObjectClass parent_class;
+
+       /* Signals */
+       GtkWindow *     (*get_dialog_parent)    (ECredentialsPrompter *prompter);
+};
+
+GType          e_credentials_prompter_get_type (void) G_GNUC_CONST;
+ECredentialsPrompter *
+               e_credentials_prompter_new      (ESourceRegistry *registry);
+ESourceRegistry *
+               e_credentials_prompter_get_registry
+                                               (ECredentialsPrompter *prompter);
+ESourceCredentialsProvider *
+               e_credentials_prompter_get_provider
+                                               (ECredentialsPrompter *prompter);
+gboolean       e_credentials_prompter_get_auto_prompt
+                                               (ECredentialsPrompter *prompter);
+void           e_credentials_prompter_set_auto_prompt
+                                               (ECredentialsPrompter *prompter,
+                                                gboolean auto_prompt);
+void           e_credentials_prompter_set_auto_prompt_disabled_for
+                                               (ECredentialsPrompter *prompter,
+                                                ESource *source,
+                                                gboolean is_disabled);
+gboolean       e_credentials_prompter_get_auto_prompt_disabled_for
+                                               (ECredentialsPrompter *prompter,
+                                                ESource *source);
+GtkWindow *    e_credentials_prompter_get_dialog_parent
+                                               (ECredentialsPrompter *prompter);
+gboolean       e_credentials_prompter_register_impl
+                                               (ECredentialsPrompter *prompter,
+                                                const gchar *authentication_method,
+                                                ECredentialsPrompterImpl *prompter_impl);
+void           e_credentials_prompter_unregister_impl
+                                               (ECredentialsPrompter *prompter,
+                                                const gchar *authentication_method,
+                                                ECredentialsPrompterImpl *prompter_impl);
+void           e_credentials_prompter_process_awaiting_credentials
+                                               (ECredentialsPrompter *prompter);
+gboolean       e_credentials_prompter_process_source
+                                               (ECredentialsPrompter *prompter,
+                                                ESource *source);
+void           e_credentials_prompter_prompt   (ECredentialsPrompter *prompter,
+                                                ESource *source,
+                                                const gchar *error_text,
+                                                ECredentialsPrompterPromptFlags flags,
+                                                GAsyncReadyCallback callback,
+                                                gpointer user_data);
+gboolean       e_credentials_prompter_prompt_finish
+                                               (ECredentialsPrompter *prompter,
+                                                GAsyncResult *result,
+                                                ESource **out_source,
+                                                ENamedParameters **out_credentials,
+                                                GError **error);
+void           e_credentials_prompter_complete_prompt_call
+                                               (ECredentialsPrompter *prompter,
+                                                GSimpleAsyncResult *async_result,
+                                                ESource *source,
+                                                const ENamedParameters *credentials,
+                                                const GError *error);
+gboolean       e_credentials_prompter_loop_prompt_sync
+                                               (ECredentialsPrompter *prompter,
+                                                ESource *source,
+                                                ECredentialsPrompterPromptFlags flags,
+                                                ECredentialsPrompterLoopPromptFunc func,
+                                                gpointer user_data,
+                                                GCancellable *cancellable,
+                                                GError **error);
+G_END_DECLS
+
+#endif /* E_CREDENTIALS_PROMPTER_H */
diff --git a/libedataserverui/e-trust-prompt.c b/libedataserverui/e-trust-prompt.c
new file mode 100644
index 0000000..8c1772a
--- /dev/null
+++ b/libedataserverui/e-trust-prompt.c
@@ -0,0 +1,672 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#define GCR_API_SUBJECT_TO_CHANGE
+#include <gcr/gcr.h>
+#undef GCR_API_SUBJECT_TO_CHANGE
+
+#include <camel/camel.h>
+#include <libebackend/libebackend.h>
+#include <libedataserver/libedataserver.h>
+
+#include "e-trust-prompt.h"
+
+static void
+trust_prompt_add_info_line (GtkGrid *grid,
+                            const gchar *label_text,
+                            const gchar *value_text,
+                            gboolean ellipsize,
+                           gboolean wrap,
+                           gboolean use_bold,
+                            gint *at_row)
+{
+       GtkWidget *widget;
+       PangoAttribute *attr;
+       PangoAttrList *bold;
+
+       g_return_if_fail (grid != NULL);
+       g_return_if_fail (label_text != NULL);
+       g_return_if_fail (at_row != NULL);
+
+       if (!value_text || !*value_text)
+               return;
+
+       bold = pango_attr_list_new ();
+       attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
+       pango_attr_list_insert (bold, attr);
+
+       widget = gtk_label_new (label_text);
+       gtk_misc_set_padding (GTK_MISC (widget), 0, 0);
+       gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.0);
+
+       gtk_grid_attach (grid, widget, 1, *at_row, 1, 1);
+
+       widget = gtk_label_new (value_text);
+       gtk_label_set_line_wrap (GTK_LABEL (widget), wrap);
+       g_object_set (
+               G_OBJECT (widget),
+               "hexpand", TRUE,
+               "halign", GTK_ALIGN_FILL,
+               "justify", GTK_JUSTIFY_LEFT,
+               "attributes", use_bold ? bold : NULL,
+               "selectable", TRUE,
+               "ellipsize", ellipsize ? PANGO_ELLIPSIZE_END : PANGO_ELLIPSIZE_NONE,
+               "width-chars", 60,
+               "max-width-chars", 80,
+               "xalign", 0.0,
+               "yalign", 0.0,
+               NULL);
+
+       gtk_grid_attach (grid, widget, 2, *at_row, 1, 1);
+
+       *at_row = (*at_row) + 1;
+
+       pango_attr_list_unref (bold);
+}
+
+static ETrustPromptResponse
+trust_prompt_show (GtkWindow *parent,
+                  const gchar *source_extension,
+                  const gchar *source_display_name,
+                  const gchar *host,
+                  const gchar *error_text,
+                  GcrParsed *parsed,
+                  const gchar *reason,
+                  void (* dialog_ready_cb) (GtkDialog *dialog, gpointer user_data),
+                  gpointer user_data)
+{
+       ETrustPromptResponse response;
+       GcrCertificateWidget *certificate_widget;
+       GcrCertificate *certificate;
+       GckAttributes *attributes;
+       GtkWidget *dialog, *widget;
+       GtkGrid *grid;
+       const guchar *data;
+       gchar *bhost, *tmp;
+       gsize length;
+       gint row = 0;
+
+       dialog = gtk_dialog_new_with_buttons (
+               _("Certificate trust..."), parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+               _("_Cancel"), GTK_RESPONSE_CANCEL,
+               _("_Reject"), GTK_RESPONSE_REJECT,
+               _("Accept _Temporarily"), GTK_RESPONSE_YES,
+               _("_Accept Permanently"), GTK_RESPONSE_ACCEPT,
+               NULL);
+
+       widget = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+       gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+
+       grid = g_object_new (
+               GTK_TYPE_GRID,
+               "orientation", GTK_ORIENTATION_HORIZONTAL,
+               "row-homogeneous", FALSE,
+               "row-spacing", 6,
+               "column-homogeneous", FALSE,
+               "column-spacing", 12,
+               "hexpand", TRUE,
+               "halign", GTK_ALIGN_FILL,
+               "vexpand", TRUE,
+               "valign", GTK_ALIGN_FILL,
+               NULL);
+
+       gtk_container_set_border_width (GTK_CONTAINER (grid), 5);
+       gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (grid));
+
+       widget = gtk_image_new_from_icon_name ("dialog-warning", GTK_ICON_SIZE_DIALOG);
+       g_object_set (
+               G_OBJECT (widget),
+               "vexpand", FALSE,
+               "valign", GTK_ALIGN_START,
+               NULL);
+       gtk_grid_attach (grid, widget, 0, row, 1, 3);
+
+       tmp = g_markup_escape_text (host, -1);
+       bhost = g_strconcat ("<b>", tmp, "</b>", NULL);
+       g_free (tmp);
+       tmp = NULL;
+       if (source_extension && source_display_name) {
+               gchar *bsource_display_name = g_strconcat ("<b>", source_display_name, "</b>", NULL);
+
+               if (g_str_equal (source_extension, E_SOURCE_EXTENSION_ADDRESS_BOOK)) {
+                       tmp = g_strdup_printf (
+                               "An address book '%s' cannot connect, because an SSL certificate for '%s' is 
not trusted. Do you wish to accept it?",
+                               bsource_display_name, bhost);
+               } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_CALENDAR)) {
+                       tmp = g_strdup_printf (
+                               "A calendar '%s' cannot connect, because an SSL certificate for '%s' is not 
trusted. Do you wish to accept it?",
+                               bsource_display_name, bhost);
+               } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_MEMO_LIST)) {
+                       tmp = g_strdup_printf (
+                               "A memo list '%s' cannot connect, because an SSL certificate for '%s' is not 
trusted. Do you wish to accept it?",
+                               bsource_display_name, bhost);
+               } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_TASK_LIST)) {
+                       tmp = g_strdup_printf (
+                               "A task list '%s' cannot connect, because an SSL certificate for '%s' is not 
trusted. Do you wish to accept it?",
+                               bsource_display_name, bhost);
+               } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
+                       tmp = g_strdup_printf (
+                               "A mail account '%s' cannot connect, because an SSL certificate for '%s' is 
not trusted. Do you wish to accept it?",
+                               bsource_display_name, bhost);
+               } else if (g_str_equal (source_extension, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
+                       tmp = g_strdup_printf (
+                               "A mail transport '%s' cannot connect, because an SSL certificate for '%s' is 
not trusted. Do you wish to accept it?",
+                               bsource_display_name, bhost);
+               } else {
+                       tmp = g_strdup_printf (
+                               "An account '%s' cannot connect, because an SSL certificate for '%s' is not 
trusted. Do you wish to accept it?",
+                               bsource_display_name, bhost);
+               }
+
+               g_free (bsource_display_name);
+       }
+       if (!tmp)
+               tmp = g_strdup_printf (_("SSL certificate for '%s' is not trusted. Do you wish to accept 
it?"), bhost);
+       g_free (bhost);
+
+       widget = gtk_label_new (NULL);
+       gtk_label_set_line_wrap (GTK_LABEL (widget), TRUE);
+       gtk_label_set_markup (GTK_LABEL (widget), tmp);
+       g_object_set (
+               G_OBJECT (widget),
+               "hexpand", TRUE,
+               "halign", GTK_ALIGN_FILL,
+               "valign", GTK_ALIGN_CENTER,
+               "width-chars", 60,
+               "max-width-chars", 80,
+               "xalign", 0.0,
+               "yalign", 0.0,
+               NULL);
+
+       g_free (tmp);
+
+       gtk_grid_attach (grid, widget, 1, row, 2, 1);
+       row++;
+
+       trust_prompt_add_info_line (grid, _("Reason:"), reason, FALSE, FALSE, TRUE, &row);
+
+       if (error_text)
+               trust_prompt_add_info_line (grid, _("Detailed error:"), error_text, FALSE, TRUE, FALSE, &row);
+
+       data = gcr_parsed_get_data (parsed, &length);
+       attributes = gcr_parsed_get_attributes (parsed);
+
+       certificate = gcr_simple_certificate_new (data, length);
+
+       certificate_widget = gcr_certificate_widget_new (certificate);
+       gcr_certificate_widget_set_attributes (certificate_widget, attributes);
+
+       widget = GTK_WIDGET (certificate_widget);
+       gtk_grid_attach (grid, widget, 1, row, 2, 1);
+       gtk_widget_show (widget);
+
+       g_clear_object (&certificate);
+
+       gtk_widget_show_all (GTK_WIDGET (grid));
+
+       if (dialog_ready_cb)
+               dialog_ready_cb (GTK_DIALOG (dialog), user_data);
+
+       switch (gtk_dialog_run (GTK_DIALOG (dialog))) {
+       case GTK_RESPONSE_REJECT:
+               response = E_TRUST_PROMPT_RESPONSE_REJECT;
+               break;
+       case GTK_RESPONSE_ACCEPT:
+               response = E_TRUST_PROMPT_RESPONSE_ACCEPT;
+               break;
+       case GTK_RESPONSE_YES:
+               response = E_TRUST_PROMPT_RESPONSE_ACCEPT_TEMPORARILY;
+               break;
+       default:
+               response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
+               break;
+       }
+
+       gtk_widget_destroy (dialog);
+
+       return response;
+}
+
+/**
+ * e_trust_prompt_describe_certificate_errors:
+ * @flags: a #GTlsCertificateFlags to describe
+ *
+ * Converts @flags into a localized text description of the set bits, one
+ * bit description per line. If no bit is set, then an empty string is
+ * returned.
+ *
+ * Returns: (transfer-full): A newly allocated string with text description
+ *  of @flags. Free the returned pointer with g_free() when no longer needed.
+ *
+ * Since: 3.14
+ **/
+gchar *
+e_trust_prompt_describe_certificate_errors (GTlsCertificateFlags flags)
+{
+       struct _convert_table {
+               GTlsCertificateFlags flag;
+               const gchar *description;
+       } convert_table[] = {
+               { G_TLS_CERTIFICATE_UNKNOWN_CA,
+                 N_("The signing certificate authority is not known.") },
+               { G_TLS_CERTIFICATE_BAD_IDENTITY,
+                 N_("The certificate does not match the expected identity of the site that it was retrieved 
from.") },
+               { G_TLS_CERTIFICATE_NOT_ACTIVATED,
+                 N_("The certificate's activation time is still in the future.") },
+               { G_TLS_CERTIFICATE_EXPIRED,
+                 N_("The certificate has expired.") },
+               { G_TLS_CERTIFICATE_REVOKED,
+                 N_("The certificate has been revoked according to the connection's certificate revocation 
list.") },
+               { G_TLS_CERTIFICATE_INSECURE,
+                 N_("The certificate's algorithm is considered insecure.") }
+       };
+
+       GString *reason = g_string_new ("");
+       gint ii;
+
+       for (ii = 0; ii < G_N_ELEMENTS (convert_table); ii++) {
+               if ((flags & convert_table[ii].flag) != 0) {
+                       if (reason->len > 0)
+                               g_string_append (reason, "\n");
+
+                       g_string_append (reason, _(convert_table[ii].description));
+               }
+       }
+
+       return g_string_free (reason, FALSE);
+}
+
+static void
+trust_prompt_parser_parsed_cb (GcrParser *parser,
+                              GcrParsed **out_parsed)
+{
+       GcrParsed *parsed;
+
+       parsed = gcr_parser_get_parsed (parser);
+       g_return_if_fail (parsed != NULL);
+
+       *out_parsed = gcr_parsed_ref (parsed);
+}
+
+static ETrustPromptResponse
+e_trust_prompt_run_with_dialog_ready_callback (GtkWindow *parent,
+                                              const gchar *source_extension,
+                                              const gchar *source_display_name,
+                                              const gchar *host,
+                                              const gchar *certificate_pem,
+                                              GTlsCertificateFlags certificate_errors,
+                                              const gchar *error_text,
+                                              void (* dialog_ready_cb) (GtkDialog *dialog, gpointer 
user_data),
+                                              gpointer user_data)
+{
+       ETrustPromptResponse response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
+       GcrParser *parser;
+       GcrParsed *parsed = NULL;
+       GError *local_error = NULL;
+
+       if (parent)
+               g_return_val_if_fail (GTK_IS_WINDOW (parent), E_TRUST_PROMPT_RESPONSE_UNKNOWN);
+       g_return_val_if_fail (host != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
+       g_return_val_if_fail (certificate_pem != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
+
+       /* Continue even if PKCS#11 module registration fails.
+        * Certificate details won't display correctly but the
+        * user can still respond to the prompt. */
+       gcr_pkcs11_initialize (NULL, &local_error);
+       if (local_error != NULL) {
+               g_warning ("%s: gcr_pkcs11_initialize() call failed: %s", G_STRFUNC, local_error->message);
+               g_clear_error (&local_error);
+       }
+
+       parser = gcr_parser_new ();
+
+       g_signal_connect (
+               parser, "parsed",
+               G_CALLBACK (trust_prompt_parser_parsed_cb), &parsed);
+
+       gcr_parser_parse_data (parser, (const guchar *) certificate_pem, strlen (certificate_pem), 
&local_error);
+
+       g_object_unref (parser);
+
+       /* Sanity check. */
+       g_warn_if_fail (
+               ((parsed != NULL) && (local_error == NULL)) ||
+               ((parsed == NULL) && (local_error != NULL)));
+
+       if (parsed != NULL) {
+               gchar *reason;
+
+               reason = e_trust_prompt_describe_certificate_errors (certificate_errors);
+
+               response = trust_prompt_show (parent, source_extension, source_display_name, host, 
error_text, parsed, reason, dialog_ready_cb, user_data);
+
+               gcr_parsed_unref (parsed);
+               g_free (reason);
+       }
+
+       g_clear_error (&local_error);
+
+       return response;
+}
+
+/**
+ * e_trust_prompt_run_modal:
+ * @parent: A #GtkWindow to use as a parent for the trust prompt dialog
+ * @source_extension: (allow none): an #ESource extension, to identify a kind of the source; or %NULL
+ * @source_display_name: (allow none): an #ESource display name, to identify what prompts; or %NULL
+ * @host: a host name to which the certificate belongs
+ * @certificate_pem: a PEM-encoded certificate for which to show the trust prompt
+ * @certificate_errors: errors of the @certificate_pem
+ * @error_text: (allow none): an optional error text to show in the dialog; can be %NULL
+ *
+ * Runs modal (doesn't return until the dialog is closed) a trust prompt dialog,
+ * it is a prompt whether a user wants to accept or reject the @certificate_pem
+ * for the @host due to the @certificate_errors errors.
+ *
+ * The pair @source_extension and @source_display_name influences the trust prompt message.
+ * If both are set, then the message also contains which source failed to connect according
+ * to these two arguments.
+ *
+ * The dialog can contain a custom error text, passed in as @error_text.
+ * The error might be a detailed error string returned by the server. If set,
+ * it is prefixed with "Detailed error:" string.
+ *
+ * Returns: A code of the user's choice. The #E_TRUST_PROMPT_RESPONSE_UNKNOWN
+ *    is returned, when the user cancelled the trust prompt dialog.
+ *
+ * Since: 3.14
+ **/
+ETrustPromptResponse
+e_trust_prompt_run_modal (GtkWindow *parent,
+                         const gchar *source_extension,
+                         const gchar *source_display_name,
+                         const gchar *host,
+                         const gchar *certificate_pem,
+                         GTlsCertificateFlags certificate_errors,
+                         const gchar *error_text)
+{
+       if (parent)
+               g_return_val_if_fail (GTK_IS_WINDOW (parent), E_TRUST_PROMPT_RESPONSE_UNKNOWN);
+       g_return_val_if_fail (host != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
+       g_return_val_if_fail (certificate_pem != NULL, E_TRUST_PROMPT_RESPONSE_UNKNOWN);
+
+       return e_trust_prompt_run_with_dialog_ready_callback (parent, source_extension, source_display_name, 
host,
+               certificate_pem, certificate_errors, error_text, NULL, NULL);
+}
+
+static void
+source_connection_status_changed_cb (ESource *source,
+                                    GParamSpec *param,
+                                    GtkDialog *dialog)
+{
+       g_return_if_fail (GTK_IS_DIALOG (dialog));
+
+       /* Do not close the prompt when the source is still waiting for the credentials. */
+       if (e_source_get_connection_status (source) != E_SOURCE_CONNECTION_STATUS_AWAITING_CREDENTIALS &&
+           e_source_get_connection_status (source) != E_SOURCE_CONNECTION_STATUS_SSL_FAILED)
+               gtk_dialog_response (dialog, GTK_RESPONSE_CANCEL);
+}
+
+static void
+trust_prompt_listen_for_source_changes_cb (GtkDialog *dialog,
+                                          gpointer user_data)
+{
+       ESource *source = user_data;
+
+       g_return_if_fail (GTK_IS_DIALOG (dialog));
+       g_return_if_fail (E_IS_SOURCE (source));
+
+       g_signal_connect (source, "notify::connection-status",
+               G_CALLBACK (source_connection_status_changed_cb), dialog);
+}
+
+typedef struct _SaveSourceData {
+       ETrustPromptResponse response;
+       gboolean call_save;
+       GError *error;
+} SaveSourceData;
+
+static void
+save_source_data_free (gpointer ptr)
+{
+       SaveSourceData *data = ptr;
+
+       if (data) {
+               g_clear_error (&data->error);
+               g_free (data);
+       }
+}
+
+static void
+save_source_thread (GTask *task,
+                   gpointer source_object,
+                   gpointer task_data,
+                   GCancellable *cancellable)
+{
+       ESource *source = source_object;
+       SaveSourceData *data = task_data;
+       GError *local_error = NULL;
+
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (data != NULL);
+
+       if (data->error)
+               local_error = g_error_copy (data->error);
+       else if (data->call_save)
+               e_source_write_sync (source, cancellable, &local_error);
+
+       if (local_error != NULL) {
+               g_task_return_error (task, local_error);
+       } else {
+               g_task_return_boolean (task, TRUE);
+       }
+}
+
+/**
+ * e_trust_prompt_run_for_source:
+ * @parent: A #GtkWindow to use as a parent for the trust prompt dialog
+ * @source: an #ESource, with %E_SOURCE_EXTENSION_AUTHENTICATION
+ * @certificate_pem: a PEM-encoded certificate for which to show the trust prompt
+ * @certificate_errors: errors of the @certificate_pem
+ * @error_text: (allow none): an optional error text to show in the dialog; can be %NULL
+ * @allow_source_save: whether can also save any @source changes
+ * @cancellable: (allow none): a #GCancellable, or %NULL
+ * @callback: a callback to call, when the prompt (an @source save) is done
+ * @user_data: user data passed into @callback
+ *
+ * Similar to e_trust_prompt_run_modal(), except it also manages all the necessary things
+ * around the @source<!-- -->'s SSL trust properties when it also contains %E_SOURCE_EXTENSION_WEBDAV,
+ * thus the SSL trust on the WebDAV @source is properly updated based on the user's choice.
+ * The call is finished with e_trust_prompt_run_for_source_finish(),
+ * which also returns the user's choice. The finish happens in the @callback.
+ * This is necessary, because the @source can be also saved.
+ *
+ * The function fails, if the @source doesn't contain the %E_SOURCE_EXTENSION_AUTHENTICATION.
+ *
+ * Note: The dialog is not shown when the stored certificate trust in the WebDAV @source
+ *    matches the @certificate_pem and the stored result is #E_TRUST_PROMPT_RESPONSE_REJECT.
+ *
+ * Since: 3.14
+ **/
+void
+e_trust_prompt_run_for_source (GtkWindow *parent,
+                              ESource *source,
+                              const gchar *certificate_pem,
+                              GTlsCertificateFlags certificate_errors,
+                              const gchar *error_text,
+                              gboolean allow_source_save,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
+{
+       ESourceAuthentication *extension_authentication;
+       ESourceWebdav *extension_webdav = NULL;
+       SaveSourceData *save_data;
+       GTlsCertificate *certificate;
+       gchar *host;
+       GTask *task;
+
+       if (parent)
+               g_return_if_fail (GTK_IS_WINDOW (parent));
+       g_return_if_fail (E_IS_SOURCE (source));
+       g_return_if_fail (certificate_pem != NULL);
+       g_return_if_fail (e_source_has_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION));
+
+       extension_authentication = e_source_get_extension (source, E_SOURCE_EXTENSION_AUTHENTICATION);
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND))
+               extension_webdav = e_source_get_extension (source, E_SOURCE_EXTENSION_WEBDAV_BACKEND);
+
+       save_data = g_new0 (SaveSourceData, 1);
+       save_data->response = E_TRUST_PROMPT_RESPONSE_UNKNOWN;
+       save_data->call_save = FALSE;
+
+       host = e_source_authentication_dup_host (extension_authentication);
+
+       certificate = g_tls_certificate_new_from_pem (certificate_pem, -1, &save_data->error);
+       if (certificate) {
+               if (extension_webdav)
+                       save_data->response = e_source_webdav_verify_ssl_trust (extension_webdav, host, 
certificate, 0);
+               else
+                       save_data->response = E_TRUST_PROMPT_RESPONSE_REJECT_TEMPORARILY;
+
+               if (save_data->response != E_TRUST_PROMPT_RESPONSE_REJECT) {
+                       const gchar *source_extension = NULL;
+
+                       if (e_source_has_extension (source, E_SOURCE_EXTENSION_ADDRESS_BOOK))
+                               source_extension = E_SOURCE_EXTENSION_ADDRESS_BOOK;
+
+                       if (e_source_has_extension (source, E_SOURCE_EXTENSION_CALENDAR)) {
+                               if (!source_extension)
+                                       source_extension = E_SOURCE_EXTENSION_CALENDAR;
+                               else
+                                       source_extension = E_SOURCE_EXTENSION_COLLECTION;
+                       }
+
+                       if (e_source_has_extension (source, E_SOURCE_EXTENSION_MEMO_LIST)) {
+                               if (!source_extension)
+                                       source_extension = E_SOURCE_EXTENSION_MEMO_LIST;
+                               else
+                                       source_extension = E_SOURCE_EXTENSION_COLLECTION;
+                       }
+
+                       if (e_source_has_extension (source, E_SOURCE_EXTENSION_TASK_LIST)) {
+                               if (!source_extension)
+                                       source_extension = E_SOURCE_EXTENSION_TASK_LIST;
+                               else
+                                       source_extension = E_SOURCE_EXTENSION_COLLECTION;
+                       }
+
+                       if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT)) {
+                               if (!source_extension)
+                                       source_extension = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
+                               else
+                                       source_extension = E_SOURCE_EXTENSION_COLLECTION;
+                       }
+
+                       if (e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_TRANSPORT)) {
+                               if (!source_extension)
+                                       source_extension = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
+                               else
+                                       source_extension = E_SOURCE_EXTENSION_COLLECTION;
+                       }
+
+                       save_data->response = e_trust_prompt_run_with_dialog_ready_callback (parent,
+                               source_extension, e_source_get_display_name (source), host,
+                               certificate_pem, certificate_errors, error_text,
+                               trust_prompt_listen_for_source_changes_cb, source);
+               }
+       }
+
+       g_signal_handlers_disconnect_matched (source, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+               source_connection_status_changed_cb, NULL);
+
+       if (save_data->response != E_TRUST_PROMPT_RESPONSE_UNKNOWN) {
+               if (certificate && extension_webdav) {
+                       e_source_webdav_update_ssl_trust (extension_webdav, host, certificate, 
save_data->response);
+                       save_data->call_save = allow_source_save;
+               }
+       }
+
+       g_clear_object (&certificate);
+       g_free (host);
+
+       task = g_task_new (source, cancellable, callback, user_data);
+       g_task_set_source_tag (task, e_trust_prompt_run_for_source);
+       g_task_set_task_data (task, save_data, save_source_data_free);
+
+       g_task_run_in_thread (task, save_source_thread);
+
+       g_object_unref (task);
+}
+
+/**
+ * e_trust_prompt_run_for_source_finish:
+ * @source: an #ESource which was used with e_trust_prompt_run_for_source()
+ * @result: a #GAsyncResult
+ * @response: an output argument, user's response to the trust prompt
+ * @error: return location for a #GError, or %NULL
+ *
+ * Finishes the operation started with e_trust_prompt_run_for_source().
+ * The @response will contain a code of the user's choice.
+ * The #E_TRUST_PROMPT_RESPONSE_UNKNOWN is used, when the user cancelled the trust
+ * prompt dialog and no changes are made with the @source.
+ *
+ * If an error occurs, the function sets @error and returns %FALSE.
+ *
+ * Returns: %TRUE on success, %FALSE on error
+ *
+ * Since: 3.14
+ **/
+gboolean
+e_trust_prompt_run_for_source_finish (ESource *source,
+                                     GAsyncResult *result,
+                                     ETrustPromptResponse *response,
+                                     GError **error)
+{
+       gboolean success;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (g_task_is_valid (result, source), FALSE);
+       g_return_val_if_fail (response != NULL, FALSE);
+
+       g_return_val_if_fail (
+               g_async_result_is_tagged (
+               result, e_trust_prompt_run_for_source), FALSE);
+
+       success = g_task_propagate_boolean (G_TASK (result), error);
+
+       if (success) {
+               SaveSourceData *save_data;
+
+               save_data = g_task_get_task_data (G_TASK (result));
+               g_return_val_if_fail (save_data != NULL, FALSE);
+
+               *response = save_data->response;
+       }
+
+       return success;
+}
diff --git a/libedataserverui/e-trust-prompt.h b/libedataserverui/e-trust-prompt.h
new file mode 100644
index 0000000..27b9835
--- /dev/null
+++ b/libedataserverui/e-trust-prompt.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc. (www.redhat.com)
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#if !defined (__LIBEDATASERVERUI_H_INSIDE__) && !defined (LIBEDATASERVERUI_COMPILATION)
+#error "Only <libedataserverui/libedataserverui.h> should be included directly."
+#endif
+
+#ifndef E_TRUST_PROMPT_H
+#define E_TRUST_PROMPT_H
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <gtk/gtk.h>
+
+#include <libedataserver/libedataserver.h>
+
+gchar *                e_trust_prompt_describe_certificate_errors
+                                       (GTlsCertificateFlags certificate_errors);
+ETrustPromptResponse
+               e_trust_prompt_run_modal(GtkWindow *parent,
+                                        const gchar *source_extension,
+                                        const gchar *source_display_name,
+                                        const gchar *host,
+                                        const gchar *certificate_pem,
+                                        GTlsCertificateFlags certificate_errors,
+                                        const gchar *error_text);
+
+void           e_trust_prompt_run_for_source
+                                       (GtkWindow *parent,
+                                        ESource *source,
+                                        const gchar *certificate_pem,
+                                        GTlsCertificateFlags certificate_errors,
+                                        const gchar *error_text,
+                                        gboolean allow_source_save,
+                                        GCancellable *cancellable,
+                                        GAsyncReadyCallback callback,
+                                        gpointer user_data);
+gboolean       e_trust_prompt_run_for_source_finish
+                                       (ESource *source,
+                                        GAsyncResult *result,
+                                        ETrustPromptResponse *response,
+                                        GError **error);
+
+#endif /* E_TRUST_PROMPT_H */
diff --git a/libedataserverui/libedataserverui.h b/libedataserverui/libedataserverui.h
new file mode 100644
index 0000000..19c60cb
--- /dev/null
+++ b/libedataserverui/libedataserverui.h
@@ -0,0 +1,30 @@
+/*
+ * libedataserverui.h
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef LIBEDATASERVERUI_H
+#define LIBEDATASERVERUI_H
+
+#define __LIBEDATASERVERUI_H_INSIDE__
+
+#include <libedataserverui/e-credentials-prompter.h>
+#include <libedataserverui/e-credentials-prompter-impl.h>
+#include <libedataserverui/e-credentials-prompter-impl-password.h>
+#include <libedataserverui/e-trust-prompt.h>
+
+#undef __LIBEDATASERVERUI_H_INSIDE__
+
+#endif /* LIBEDATASERVERUI_H */
diff --git a/libedataserverui/libedataserverui.pc.in b/libedataserverui/libedataserverui.pc.in
new file mode 100644
index 0000000..083a3a0
--- /dev/null
+++ b/libedataserverui/libedataserverui.pc.in
@@ -0,0 +1,18 @@
+prefix= prefix@
+exec_prefix= exec_prefix@
+libdir= libdir@
+includedir= includedir@
+datarootdir= datarootdir@
+datadir= datadir@
+
+privlibdir= privlibdir@
+privincludedir= privincludedir@
+
+credentialmoduledir= credentialmoduledir@
+
+Name: libedataserverui
+Description: UI utility library for Evolution Data Server
+Version: @VERSION@
+Requires: gio-2.0 gmodule-2.0 camel- API_VERSION@ libsecret-1 libxml-2.0 libsoup-2.4 gtk+-3.0 
libedataserver- API_VERSION@
+Libs: -L${libdir} -ledataserver- API_VERSION@ -ledataserverui- API_VERSION@
+Cflags: -I${privincludedir}
diff --git a/modules/gnome-online-accounts/Makefile.am b/modules/gnome-online-accounts/Makefile.am
index 67448c3..808c4fd 100644
--- a/modules/gnome-online-accounts/Makefile.am
+++ b/modules/gnome-online-accounts/Makefile.am
@@ -16,8 +16,6 @@ module_gnome_online_accounts_la_SOURCES = \
        module-gnome-online-accounts.c \
        e-goa-client.c \
        e-goa-client.h \
-       e-goa-password-based.c \
-       e-goa-password-based.h \
        goaewsclient.c \
        goaewsclient.h \
        $(NULL)
@@ -36,4 +34,38 @@ module_gnome_online_accounts_la_LDFLAGS = \
        -module -avoid-version $(NO_UNDEFINED) \
        $(NULL)
 
+credentialmodule_LTLIBRARIES = module-credentials-goa.la
+
+module_credentials_goa_la_CPPFLAGS = \
+       $(AM_CPPFLAGS) \
+       -I$(top_srcdir) \
+       -DG_LOG_DOMAIN=\"module-credentials-goa\" \
+       $(E_BACKEND_CFLAGS) \
+       $(CAMEL_CFLAGS) \
+       $(SOUP_CFLAGS) \
+       $(GOA_CFLAGS) \
+       $(NULL)
+
+module_credentials_goa_la_SOURCES = \
+       module-credentials-goa.c \
+       e-goa-client.c \
+       e-goa-client.h \
+       e-goa-password-based.c \
+       e-goa-password-based.h \
+       $(NULL)
+
+module_credentials_goa_la_LIBADD = \
+       $(top_builddir)/camel/libcamel-1.2.la \
+       $(top_builddir)/libebackend/libebackend-1.2.la \
+       $(top_builddir)/libedataserver/libedataserver-1.2.la \
+       $(E_BACKEND_LIBS) \
+       $(CAMEL_LIBS) \
+       $(SOUP_LIBS) \
+       $(GOA_LIBS) \
+       $(NULL)
+
+module_credentials_goa_la_LDFLAGS = \
+       -module -avoid-version $(NO_UNDEFINED) \
+       $(NULL)
+
 -include $(top_srcdir)/git.mk
diff --git a/modules/gnome-online-accounts/e-goa-password-based.c 
b/modules/gnome-online-accounts/e-goa-password-based.c
index 30714b0..fd05671 100644
--- a/modules/gnome-online-accounts/e-goa-password-based.c
+++ b/modules/gnome-online-accounts/e-goa-password-based.c
@@ -15,15 +15,18 @@
  *
  */
 
-#include "e-goa-password-based.h"
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
 /* XXX Yeah, yeah... */
 #define GOA_API_IS_SUBJECT_TO_CHANGE
 
-#include <config.h>
 #include <goa/goa.h>
 #include <glib/gi18n-lib.h>
 
+#include "e-goa-password-based.h"
+
 #define E_GOA_PASSWORD_BASED_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
        ((obj), E_TYPE_GOA_PASSWORD_BASED, EGoaPasswordBasedPrivate))
@@ -32,34 +35,35 @@ struct _EGoaPasswordBasedPrivate {
        gint placeholder;
 };
 
-G_DEFINE_DYNAMIC_TYPE (
-       EGoaPasswordBased,
-       e_goa_password_based,
-       E_TYPE_AUTHENTICATION_SESSION)
+G_DEFINE_DYNAMIC_TYPE (EGoaPasswordBased, e_goa_password_based, E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL)
 
 static GoaObject *
-e_goa_password_based_ref_account (ESourceRegistryServer *server,
-                                  ESource *source,
+e_goa_password_based_ref_account (ESourceCredentialsProvider *provider,
+                                 ESource *source,
                                   GoaClient *goa_client)
 {
+       ESource *cred_source = NULL;
        GoaObject *match = NULL;
        GList *list, *link;
-       const gchar *extension_name;
        gchar *account_id = NULL;
+       ESourceGoa *extension = NULL;
 
-       extension_name = E_SOURCE_EXTENSION_GOA;
-
-       source = e_source_registry_server_find_extension (
-               server, source, extension_name);
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_GOA)) {
+               extension = e_source_get_extension (source, E_SOURCE_EXTENSION_GOA);
+       } else {
+               cred_source = e_source_credentials_provider_ref_credentials_source (provider, source);
+               if (cred_source && e_source_has_extension (cred_source, E_SOURCE_EXTENSION_GOA))
+                       extension = e_source_get_extension (cred_source, E_SOURCE_EXTENSION_GOA);
+       }
 
-       if (source != NULL) {
-               ESourceGoa *extension;
+       if (!extension) {
+               g_clear_object (&cred_source);
+               return NULL;
+       }
 
-               extension = e_source_get_extension (source, extension_name);
-               account_id = e_source_goa_dup_account_id (extension);
+       account_id = e_source_goa_dup_account_id (extension);
 
-               g_object_unref (source);
-       }
+       g_clear_object (&cred_source);
 
        if (account_id == NULL)
                return NULL;
@@ -86,55 +90,83 @@ e_goa_password_based_ref_account (ESourceRegistryServer *server,
        }
 
        g_list_free_full (list, (GDestroyNotify) g_object_unref);
+       g_free (account_id);
 
        return match;
 }
 
-static EAuthenticationSessionResult
-e_goa_password_based_execute_sync (EAuthenticationSession *session,
-                                   GCancellable *cancellable,
-                                   GError **error)
+static gboolean
+e_goa_password_based_can_process (ESourceCredentialsProviderImpl *provider_impl,
+                                 ESource *source)
+{
+       gboolean can_process;
+
+       g_return_val_if_fail (E_IS_GOA_PASSWORD_BASED (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+
+       can_process = e_source_has_extension (source, E_SOURCE_EXTENSION_GOA);
+       if (!can_process) {
+               ESource *cred_source;
+
+               cred_source = e_source_credentials_provider_ref_credentials_source (
+                       e_source_credentials_provider_impl_get_provider (provider_impl),
+                       source);
+
+               if (cred_source) {
+                       can_process = e_source_has_extension (cred_source, E_SOURCE_EXTENSION_GOA);
+                       g_clear_object (&cred_source);
+               }
+       }
+
+       return can_process;
+}
+
+static gboolean
+e_goa_password_based_can_store (ESourceCredentialsProviderImpl *provider_impl)
+{
+       g_return_val_if_fail (E_IS_GOA_PASSWORD_BASED (provider_impl), FALSE);
+
+       return FALSE;
+}
+
+static gboolean
+e_goa_password_based_can_prompt (ESourceCredentialsProviderImpl *provider_impl)
+{
+       g_return_val_if_fail (E_IS_GOA_PASSWORD_BASED (provider_impl), FALSE);
+
+       return FALSE;
+}
+
+static gboolean
+e_goa_password_based_lookup_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                 ESource *source,
+                                 GCancellable *cancellable,
+                                 ENamedParameters **out_credentials,
+                                 GError **error)
 {
-       EAuthenticationSessionResult session_result;
-       ESourceAuthenticationResult auth_result;
-       ESourceAuthenticator *authenticator;
-       ESourceRegistryServer *server;
-       ESource *source = NULL;
        GoaClient *goa_client = NULL;
        GoaObject *goa_object = NULL;
        GoaAccount *goa_account = NULL;
        GoaPasswordBased *goa_password_based = NULL;
-       GString *password_string;
-       const gchar *extension_name;
-       const gchar *source_uid;
        gchar *password = NULL;
        gboolean use_imap_password;
        gboolean use_smtp_password;
-       gboolean success;
+       gboolean success = FALSE;
+
+       g_return_val_if_fail (E_IS_GOA_PASSWORD_BASED (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (out_credentials, FALSE);
 
        goa_client = goa_client_new_sync (cancellable, error);
        if (goa_client == NULL) {
-               session_result = E_AUTHENTICATION_SESSION_ERROR;
                if (error && *error)
                        g_dbus_error_strip_remote_error (*error);
                goto exit;
        }
 
-       server = e_authentication_session_get_server (session);
-       source_uid = e_authentication_session_get_source_uid (session);
-       source = e_source_registry_server_ref_source (server, source_uid);
-
-       if (source == NULL) {
-               g_set_error (
-                       error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
-                       _("No such data source for UID '%s'"),
-                       source_uid);
-               session_result = E_AUTHENTICATION_SESSION_ERROR;
-               goto exit;
-       }
-
        goa_object = e_goa_password_based_ref_account (
-               server, source, goa_client);
+               e_source_credentials_provider_impl_get_provider (provider_impl),
+               source, goa_client);
 
        if (goa_object == NULL) {
                g_set_error (
@@ -143,7 +175,6 @@ e_goa_password_based_execute_sync (EAuthenticationSession *session,
                        "the org.gnome.OnlineAccounts service from "
                        "which to obtain a password for '%s'"),
                        e_source_get_display_name (source));
-               session_result = E_AUTHENTICATION_SESSION_ERROR;
                goto exit;
        }
 
@@ -151,24 +182,18 @@ e_goa_password_based_execute_sync (EAuthenticationSession *session,
        goa_password_based = goa_object_get_password_based (goa_object);
 
        /* XXX We should only be here if the account is password based. */
-       g_return_val_if_fail (
-               goa_password_based != NULL,
-               E_AUTHENTICATION_SESSION_ERROR);
+       g_return_val_if_fail (goa_password_based != NULL, FALSE);
 
        success = goa_account_call_ensure_credentials_sync (
                goa_account, NULL, cancellable, error);
        if (!success) {
-               session_result = E_AUTHENTICATION_SESSION_ERROR;
                if (error && *error)
                        g_dbus_error_strip_remote_error (*error);
                goto exit;
        }
 
-       extension_name = E_SOURCE_EXTENSION_MAIL_ACCOUNT;
-       use_imap_password = e_source_has_extension (source, extension_name);
-
-       extension_name = E_SOURCE_EXTENSION_MAIL_TRANSPORT;
-       use_smtp_password = e_source_has_extension (source, extension_name);
+       use_imap_password = e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_ACCOUNT);
+       use_smtp_password = e_source_has_extension (source, E_SOURCE_EXTENSION_MAIL_TRANSPORT);
 
        /* Use a suitable password ID for the ESource. */
        if (use_imap_password) {
@@ -187,68 +212,38 @@ e_goa_password_based_execute_sync (EAuthenticationSession *session,
        }
 
        if (password == NULL) {
-               session_result = E_AUTHENTICATION_SESSION_ERROR;
+               success = FALSE;
                if (error && *error)
                        g_dbus_error_strip_remote_error (*error);
                goto exit;
        }
 
-       authenticator = e_authentication_session_get_authenticator (session);
-       password_string = g_string_new (password);
-       auth_result = e_source_authenticator_try_password_sync (
-               authenticator, password_string, cancellable, error);
-       g_string_free (password_string, TRUE);
-
-       switch (auth_result) {
-               case E_SOURCE_AUTHENTICATION_ERROR:
-                       session_result = E_AUTHENTICATION_SESSION_ERROR;
-                       break;
-
-               case E_SOURCE_AUTHENTICATION_ACCEPTED:
-                       session_result = E_AUTHENTICATION_SESSION_SUCCESS;
-                       break;
-
-               case E_SOURCE_AUTHENTICATION_REJECTED:
-                       /* FIXME Apparently applications are expected to post
-                        *       a desktop-wide notification about the failed
-                        *       authentication attempt. */
-                       g_set_error (
-                               error, G_IO_ERROR,
-                               G_IO_ERROR_PERMISSION_DENIED,
-                               _("Invalid password for '%s'"),
-                               e_source_get_display_name (source));
-                       session_result = E_AUTHENTICATION_SESSION_ERROR;
-                       break;
-
-               default:
-                       g_warn_if_reached ();
-                       session_result = E_AUTHENTICATION_SESSION_DISMISSED;
-                       break;
-       }
+       *out_credentials = e_named_parameters_new ();
+       e_named_parameters_set (*out_credentials, E_SOURCE_CREDENTIAL_PASSWORD, password);
 
-exit:
-       g_clear_object (&source);
+ exit:
        g_clear_object (&goa_client);
        g_clear_object (&goa_object);
        g_clear_object (&goa_account);
        g_clear_object (&goa_password_based);
 
-       g_free (password);
+       e_util_safe_free_string (password);
 
-       return session_result;
+       return success;
 }
 
 static void
 e_goa_password_based_class_init (EGoaPasswordBasedClass *class)
 {
-       EAuthenticationSessionClass *authentication_session_class;
+       ESourceCredentialsProviderImplClass *provider_impl_class;
 
        g_type_class_add_private (class, sizeof (EGoaPasswordBasedPrivate));
 
-       authentication_session_class =
-               E_AUTHENTICATION_SESSION_CLASS (class);
-       authentication_session_class->execute_sync =
-               e_goa_password_based_execute_sync;
+       provider_impl_class = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_CLASS (class);
+       provider_impl_class->can_process = e_goa_password_based_can_process;
+       provider_impl_class->can_store = e_goa_password_based_can_store;
+       provider_impl_class->can_prompt = e_goa_password_based_can_prompt;
+       provider_impl_class->lookup_sync = e_goa_password_based_lookup_sync;
 }
 
 static void
diff --git a/modules/gnome-online-accounts/e-goa-password-based.h 
b/modules/gnome-online-accounts/e-goa-password-based.h
index 40720fe..d0382e0 100644
--- a/modules/gnome-online-accounts/e-goa-password-based.h
+++ b/modules/gnome-online-accounts/e-goa-password-based.h
@@ -18,7 +18,7 @@
 #ifndef E_GOA_PASSWORD_BASED_H
 #define E_GOA_PASSWORD_BASED_H
 
-#include <libebackend/libebackend.h>
+#include <libedataserver/libedataserver.h>
 
 /* Standard GObject macros */
 #define E_TYPE_GOA_PASSWORD_BASED \
@@ -46,12 +46,12 @@ typedef struct _EGoaPasswordBasedClass EGoaPasswordBasedClass;
 typedef struct _EGoaPasswordBasedPrivate EGoaPasswordBasedPrivate;
 
 struct _EGoaPasswordBased {
-       EAuthenticationSession parent;
+       ESourceCredentialsProviderImpl parent;
        EGoaPasswordBasedPrivate *priv;
 };
 
 struct _EGoaPasswordBasedClass {
-       EAuthenticationSessionClass parent_class;
+       ESourceCredentialsProviderImplClass parent_class;
 };
 
 GType          e_goa_password_based_get_type   (void) G_GNUC_CONST;
diff --git a/modules/gnome-online-accounts/module-credentials-goa.c 
b/modules/gnome-online-accounts/module-credentials-goa.c
new file mode 100644
index 0000000..4d5ea1a
--- /dev/null
+++ b/modules/gnome-online-accounts/module-credentials-goa.c
@@ -0,0 +1,37 @@
+/*
+ * module-credentials-goa.c
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-goa-password-based.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+       e_goa_password_based_type_register (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --git a/modules/gnome-online-accounts/module-gnome-online-accounts.c 
b/modules/gnome-online-accounts/module-gnome-online-accounts.c
index 03daba0..7b34918 100644
--- a/modules/gnome-online-accounts/module-gnome-online-accounts.c
+++ b/modules/gnome-online-accounts/module-gnome-online-accounts.c
@@ -23,7 +23,6 @@
 
 #include "goaewsclient.h"
 #include "e-goa-client.h"
-#include "e-goa-password-based.h"
 
 /* Standard GObject macros */
 #define E_TYPE_GNOME_ONLINE_ACCOUNTS \
@@ -656,13 +655,6 @@ gnome_online_accounts_config_collection (EGnomeOnlineAccounts *extension,
        e_server_side_source_set_removable (
                E_SERVER_SIDE_SOURCE (source), FALSE);
 
-       if (goa_object_peek_password_based (goa_object) != NULL) {
-               /* Obtain passwords from the OnlineAccounts service. */
-               e_server_side_source_set_auth_session_type (
-                       E_SERVER_SIDE_SOURCE (source),
-                       E_TYPE_GOA_PASSWORD_BASED);
-       }
-
        if (goa_object_peek_oauth2_based (goa_object) != NULL) {
                /* This module provides OAuth 2.0 support to the collection.
                 * Note, children of the collection source will automatically
@@ -1337,7 +1329,6 @@ G_MODULE_EXPORT void
 e_module_load (GTypeModule *type_module)
 {
        e_goa_client_type_register (type_module);
-       e_goa_password_based_type_register (type_module);
        e_gnome_online_accounts_register_type (type_module);
 }
 
diff --git a/modules/owncloud-backend/module-owncloud-backend.c 
b/modules/owncloud-backend/module-owncloud-backend.c
index e13d5c5..0e898cc 100644
--- a/modules/owncloud-backend/module-owncloud-backend.c
+++ b/modules/owncloud-backend/module-owncloud-backend.c
@@ -29,6 +29,9 @@
 #define E_OWNCLOUD_BACKEND(obj) \
        (G_TYPE_CHECK_INSTANCE_CAST \
        ((obj), E_TYPE_OWNCLOUD_BACKEND, EOwncloudBackend))
+#define E_IS_OWNCLOUD_BACKEND(obj) \
+       (G_TYPE_CHECK_INSTANCE_TYPE \
+       ((obj), E_TYPE_OWNCLOUD_BACKEND))
 
 typedef struct _EOwncloudBackend EOwncloudBackend;
 typedef struct _EOwncloudBackendClass EOwncloudBackendClass;
@@ -224,14 +227,21 @@ owncloud_add_uid_to_hashtable (gpointer source,
        g_hash_table_insert (known_sources, rid, uid);
 }
 
-static gpointer
-owncloud_populate_thread (gpointer data)
+static ESourceAuthenticationResult
+owncloud_backend_authenticate_sync (EBackend *backend,
+                                   const ENamedParameters *credentials,
+                                   gchar **out_certificate_pem,
+                                   GTlsCertificateFlags *out_certificate_errors,
+                                   GCancellable *cancellable,
+                                   GError **error)
 {
-       ECollectionBackend *collection = data;
+       ECollectionBackend *collection = E_COLLECTION_BACKEND (backend);
+       ESourceAuthenticationResult result;
        GHashTable *known_sources;
        GList *sources;
+       GError *local_error = NULL;
 
-       g_return_val_if_fail (collection != NULL, NULL);
+       g_return_val_if_fail (collection != NULL, E_SOURCE_AUTHENTICATION_ERROR);
 
        /* resource-id => source's UID */
        known_sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
@@ -244,7 +254,8 @@ owncloud_populate_thread (gpointer data)
        g_list_foreach (sources, owncloud_add_uid_to_hashtable, known_sources);
        g_list_free_full (sources, g_object_unref);
 
-       if (owncloud_utils_search_server (collection, owncloud_source_found_cb, known_sources)) {
+       if (owncloud_utils_search_server (collection, credentials, out_certificate_pem, 
out_certificate_errors,
+               owncloud_source_found_cb, known_sources, cancellable, &local_error)) {
                ESourceRegistryServer *server;
 
                server = e_collection_backend_ref_server (collection);
@@ -254,10 +265,23 @@ owncloud_populate_thread (gpointer data)
                g_object_unref (server);
        }
 
+       if (local_error == NULL) {
+               result = E_SOURCE_AUTHENTICATION_ACCEPTED;
+               e_collection_backend_authenticate_children (collection, credentials);
+       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_UNAUTHORIZED)) {
+               result = E_SOURCE_AUTHENTICATION_REJECTED;
+               g_clear_error (&local_error);
+       } else if (g_error_matches (local_error, SOUP_HTTP_ERROR, SOUP_STATUS_SSL_FAILED)) {
+               result = E_SOURCE_AUTHENTICATION_ERROR_SSL_FAILED;
+               g_propagate_error (error, local_error);
+       } else {
+               result = E_SOURCE_AUTHENTICATION_ERROR;
+               g_propagate_error (error, local_error);
+       }
+
        g_hash_table_destroy (known_sources);
-       g_object_unref (collection);
 
-       return NULL;
+       return result;
 }
 
 static void
@@ -265,7 +289,6 @@ owncloud_backend_populate (ECollectionBackend *collection)
 {
        GList *list, *liter;
        ESourceRegistryServer *server;
-       GThread *thread;
 
        /* Chain up to parent's populate() method. */
        E_COLLECTION_BACKEND_CLASS (e_owncloud_backend_parent_class)->populate (collection);
@@ -292,17 +315,21 @@ owncloud_backend_populate (ECollectionBackend *collection)
        g_list_free_full (list, g_object_unref);
        g_object_unref (server);
 
-       thread = g_thread_new (NULL, owncloud_populate_thread, g_object_ref (collection));
-       g_thread_unref (thread);
+       e_backend_schedule_credentials_required (E_BACKEND (collection), E_SOURCE_CREDENTIALS_REASON_REQUIRED,
+               NULL, 0, NULL, NULL, G_STRFUNC);
 }
 
 static void
 e_owncloud_backend_class_init (EOwncloudBackendClass *class)
 {
-       ECollectionBackendClass *backend_class;
+       EBackendClass *backend_class;
+       ECollectionBackendClass *collection_backend_class;
+
+       backend_class = E_BACKEND_CLASS (class);
+       backend_class->authenticate_sync = owncloud_backend_authenticate_sync;
 
-       backend_class = E_COLLECTION_BACKEND_CLASS (class);
-       backend_class->populate = owncloud_backend_populate;
+       collection_backend_class = E_COLLECTION_BACKEND_CLASS (class);
+       collection_backend_class->populate = owncloud_backend_populate;
 }
 
 static void
diff --git a/modules/owncloud-backend/owncloud-utils.c b/modules/owncloud-backend/owncloud-utils.c
index bb860e4..dadb05d 100644
--- a/modules/owncloud-backend/owncloud-utils.c
+++ b/modules/owncloud-backend/owncloud-utils.c
@@ -31,83 +31,6 @@
 
 #include "owncloud-utils.h"
 
-typedef struct _EOwncloudAuthenticator EOwncloudAuthenticator;
-typedef struct _EOwncloudAuthenticatorClass EOwncloudAuthenticatorClass;
-
-struct _EOwncloudAuthenticator {
-       GObject parent;
-
-       ECollectionBackend *collection;
-       gchar *username;
-       GString *password;
-};
-
-struct _EOwncloudAuthenticatorClass {
-       GObjectClass parent_class;
-};
-
-static ESourceAuthenticationResult
-owncloud_authenticator_try_password_sync (ESourceAuthenticator *auth,
-                                          const GString *password,
-                                          GCancellable *cancellable,
-                                          GError **error)
-{
-       EOwncloudAuthenticator *authenticator = (EOwncloudAuthenticator *) auth;
-
-       if (authenticator->password)
-               g_string_free (authenticator->password, TRUE);
-       authenticator->password = g_string_new (password->str);
-
-       return E_SOURCE_AUTHENTICATION_ACCEPTED;
-}
-
-#define E_TYPE_OWNCLOUD_AUTHENTICATOR (e_owncloud_authenticator_get_type ())
-
-GType          e_owncloud_authenticator_get_type
-                               (void) G_GNUC_CONST;
-static void    e_owncloud_authenticator_authenticator_init
-                               (ESourceAuthenticatorInterface *iface);
-
-G_DEFINE_TYPE_EXTENDED (
-       EOwncloudAuthenticator,
-       e_owncloud_authenticator,
-       G_TYPE_OBJECT, 0,
-       G_IMPLEMENT_INTERFACE (
-               E_TYPE_SOURCE_AUTHENTICATOR,
-               e_owncloud_authenticator_authenticator_init))
-
-static void
-owncloud_authenticator_finalize (GObject *object)
-{
-       EOwncloudAuthenticator *authenticator = (EOwncloudAuthenticator *) object;
-
-       g_free (authenticator->username);
-       if (authenticator->password)
-               g_string_free (authenticator->password, TRUE);
-
-       G_OBJECT_CLASS (e_owncloud_authenticator_parent_class)->finalize (object);
-}
-
-static void
-e_owncloud_authenticator_class_init (EOwncloudAuthenticatorClass *class)
-{
-       GObjectClass *object_class;
-
-       object_class = G_OBJECT_CLASS (class);
-       object_class->finalize = owncloud_authenticator_finalize;
-}
-
-static void
-e_owncloud_authenticator_authenticator_init (ESourceAuthenticatorInterface *iface)
-{
-       iface->try_password_sync = owncloud_authenticator_try_password_sync;
-}
-
-static void
-e_owncloud_authenticator_init (EOwncloudAuthenticator *authenticator)
-{
-}
-
 #define XPATH_STATUS "string(/D:multistatus/D:response[%d]/D:propstat/D:status)"
 #define XPATH_HREF "string(/D:multistatus/D:response[%d]/D:href)"
 #define XPATH_DISPLAY_NAME "string(/D:multistatus/D:response[%d]/D:propstat/D:prop/D:displayname)"
@@ -424,6 +347,11 @@ parse_propfind_response (ECollectionBackend *collection,
        xmlFreeDoc (doc);
 }
 
+typedef struct _AuthenticateData {
+       const gchar *username;
+       const ENamedParameters *credentials;
+} AuthenticateData;
+
 static void
 authenticate_cb (SoupSession *session,
                  SoupMessage *msg,
@@ -431,38 +359,17 @@ authenticate_cb (SoupSession *session,
                  gboolean retrying,
                  gpointer user_data)
 {
-       EOwncloudAuthenticator *authenticator = user_data;
-
-       g_return_if_fail (authenticator != NULL);
-
-       if (retrying || !authenticator->password) {
-               ESourceRegistryServer *server;
-               EAuthenticationSession *auth_session;
-               ESource *source;
-
-               source = e_backend_get_source (
-                       E_BACKEND (authenticator->collection));
-               server = e_collection_backend_ref_server (
-                       authenticator->collection);
-
-               auth_session = e_source_registry_server_new_auth_session (
-                       server,
-                       E_SOURCE_AUTHENTICATOR (authenticator),
-                       e_source_get_uid (source));
-               if (!e_source_registry_server_authenticate_sync (server, auth_session, NULL, NULL)) {
-                       if (authenticator->password)
-                               g_string_free (authenticator->password, TRUE);
-                       authenticator->password = NULL;
-               }
+       AuthenticateData *auth_data = user_data;
 
-               g_object_unref (auth_session);
-               g_object_unref (server);
-       }
+       g_return_if_fail (auth_data != NULL);
+       g_return_if_fail (auth_data->credentials != NULL);
+
+       if (retrying)
+               return;
 
-       if (authenticator->username && authenticator->password)
-               soup_auth_authenticate (
-                       auth, authenticator->username,
-                       authenticator->password->str);
+       if (auth_data->username && e_named_parameters_get (auth_data->credentials, 
E_SOURCE_CREDENTIAL_PASSWORD))
+               soup_auth_authenticate (auth, auth_data->username,
+                       e_named_parameters_get (auth_data->credentials, E_SOURCE_CREDENTIAL_PASSWORD));
 }
 
 static gboolean
@@ -471,7 +378,12 @@ find_sources (ECollectionBackend *collection,
               gpointer user_data,
               const gchar *base_url,
               const gchar *base_collection_path,
-              EOwncloudAuthenticator *authenticator)
+             const ENamedParameters *credentials,
+             const gchar *default_username,
+             gchar **out_certificate_pem,
+             GTlsCertificateFlags *out_certificate_errors,
+             GCancellable *cancellable,
+             GError **error)
 {
        const gchar *req_body =
                "<D:propfind "
@@ -486,21 +398,26 @@ find_sources (ECollectionBackend *collection,
                "  </D:prop>\n"
                "</D:propfind>\n";
 
+       AuthenticateData auth_data;
        SoupSession *session;
        SoupMessage *msg;
        GString *url;
+       const gchar *username;
        gboolean tested = FALSE;
 
        g_return_val_if_fail (base_url && *base_url, FALSE);
        g_return_val_if_fail (base_collection_path && *base_collection_path, FALSE);
-       g_return_val_if_fail (authenticator, FALSE);
+
+       username = e_named_parameters_get (credentials, E_SOURCE_CREDENTIAL_USERNAME);
+       if (!username || !*username)
+               username = default_username;
 
        url = g_string_new (base_url);
        if (url->str[url->len - 1] != '/')
                g_string_append_c (url, '/');
        g_string_append (url, base_collection_path);
        g_string_append_c (url, '/');
-       g_string_append (url, authenticator->username);
+       g_string_append (url, username);
        g_string_append_c (url, '/');
 
        msg = soup_message_new ("PROPFIND", url->str);
@@ -510,6 +427,9 @@ find_sources (ECollectionBackend *collection,
                return FALSE;
        }
 
+       auth_data.username = username;
+       auth_data.credentials = credentials;
+
        session = soup_session_sync_new ();
        g_object_set (
                session,
@@ -519,7 +439,7 @@ find_sources (ECollectionBackend *collection,
                NULL);
        g_signal_connect (
                session, "authenticate",
-               G_CALLBACK (authenticate_cb), authenticator);
+               G_CALLBACK (authenticate_cb), &auth_data);
 
        g_object_bind_property (
                collection, "proxy-resolver",
@@ -532,9 +452,7 @@ find_sources (ECollectionBackend *collection,
                msg, "application/xml; charset=utf-8",
                SOUP_MEMORY_STATIC, req_body, strlen (req_body));
 
-       /* this is the master source, thus there is no parent_source */
-       e_soup_ssl_trust_connect (
-               msg, e_backend_get_source (E_BACKEND (collection)), NULL, NULL);
+       e_soup_ssl_trust_connect (msg, e_backend_get_source (E_BACKEND (collection)));
 
        soup_session_send_message (session, msg);
 
@@ -551,6 +469,22 @@ find_sources (ECollectionBackend *collection,
 
                soup_uri_free (suri);
                tested = TRUE;
+       } else {
+               g_set_error_literal (error, SOUP_HTTP_ERROR, msg->status_code, msg->reason_phrase);
+
+               if (msg->status_code == SOUP_STATUS_SSL_FAILED && out_certificate_pem && 
out_certificate_errors) {
+                       GTlsCertificate *certificate = NULL;
+
+                       g_object_get (G_OBJECT (msg),
+                               "tls-certificate", &certificate,
+                               "tls-errors", out_certificate_errors,
+                               NULL);
+
+                       if (certificate) {
+                               g_object_get (certificate, "certificate-pem", out_certificate_pem, NULL);
+                               g_object_unref (certificate);
+                       }
+               }
        }
 
        g_object_unref (msg);
@@ -561,16 +495,21 @@ find_sources (ECollectionBackend *collection,
 
 gboolean
 owncloud_utils_search_server (ECollectionBackend *collection,
+                             const ENamedParameters *credentials,
+                             gchar **out_certificate_pem,
+                             GTlsCertificateFlags *out_certificate_errors,
                               OwnCloudSourceFoundCb found_cb,
-                              gpointer user_data)
+                              gpointer user_data,
+                             GCancellable *cancellable,
+                             GError **error)
 {
        ESourceCollection *collection_extension;
        ESourceGoa *goa_extension;
        ESource *source;
-       EOwncloudAuthenticator *authenticator;
-       gchar *url;
+       gchar *url, *username;
        gboolean res_calendars = FALSE;
        gboolean res_contacts = FALSE;
+       GError *local_error = NULL;
 
        g_return_val_if_fail (collection != NULL, FALSE);
        g_return_val_if_fail (found_cb != NULL, FALSE);
@@ -579,9 +518,7 @@ owncloud_utils_search_server (ECollectionBackend *collection,
        collection_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_COLLECTION);
        goa_extension = e_source_get_extension (source, E_SOURCE_EXTENSION_GOA);
 
-       authenticator = g_object_new (E_TYPE_OWNCLOUD_AUTHENTICATOR, NULL);
-       authenticator->collection = collection;
-       authenticator->username = e_source_collection_dup_identity (collection_extension);
+       username = e_source_collection_dup_identity (collection_extension);
 
        if (e_source_collection_get_calendar_enabled (collection_extension)) {
                url = e_source_goa_dup_calendar_url (goa_extension);
@@ -589,23 +526,30 @@ owncloud_utils_search_server (ECollectionBackend *collection,
                if (url && *url)
                        res_calendars = find_sources (
                                collection, found_cb, user_data,
-                               url, "calendars", authenticator);
+                               url, "calendars", credentials, username,
+                               out_certificate_pem, out_certificate_errors,
+                               cancellable, &local_error);
 
                g_free (url);
        }
 
-       if (e_source_collection_get_contacts_enabled (collection_extension)) {
+       if (e_source_collection_get_contacts_enabled (collection_extension) && !local_error) {
                url = e_source_goa_dup_contacts_url (goa_extension);
 
                if (url && *url)
                        res_contacts = find_sources (
                                collection, found_cb, user_data,
-                               url, "addressbooks", authenticator);
+                               url, "addressbooks", credentials, username,
+                               out_certificate_pem, out_certificate_errors,
+                               cancellable, &local_error);
 
                g_free (url);
        }
 
-       g_object_unref (authenticator);
+       if (local_error)
+               g_propagate_error (error, local_error);
+
+       g_free (username);
 
        return res_calendars || res_contacts;
 }
diff --git a/modules/owncloud-backend/owncloud-utils.h b/modules/owncloud-backend/owncloud-utils.h
index 00bea18..fe184d8 100644
--- a/modules/owncloud-backend/owncloud-utils.h
+++ b/modules/owncloud-backend/owncloud-utils.h
@@ -38,8 +38,13 @@ typedef void (*OwnCloudSourceFoundCb)        (ECollectionBackend *collection,
                                                 gpointer user_data);
 
 gboolean       owncloud_utils_search_server    (ECollectionBackend *collection,
+                                                const ENamedParameters *credentials,
+                                                gchar **out_certificate_pem,
+                                                GTlsCertificateFlags *out_certificate_errors,
                                                 OwnCloudSourceFoundCb found_cb,
-                                                gpointer user_data);
+                                                gpointer user_data,
+                                                GCancellable *cancellable,
+                                                GError **error);
 
 G_END_DECLS
 
diff --git a/modules/ubuntu-online-accounts/Makefile.am b/modules/ubuntu-online-accounts/Makefile.am
index 0a268d4..e3ba0e6 100644
--- a/modules/ubuntu-online-accounts/Makefile.am
+++ b/modules/ubuntu-online-accounts/Makefile.am
@@ -16,8 +16,6 @@ module_ubuntu_online_accounts_la_CPPFLAGS = \
 
 module_ubuntu_online_accounts_la_SOURCES = \
        module-ubuntu-online-accounts.c \
-       e-signon-session-password.c \
-       e-signon-session-password.h \
        uoa-utils.c \
        uoa-utils.h \
        $(NULL)
@@ -37,6 +35,42 @@ module_ubuntu_online_accounts_la_LDFLAGS = \
        -module -avoid-version $(NO_UNDEFINED) \
        $(NULL)
 
+credentialmodule_LTLIBRARIES = module-credentials-uoa.la
+
+module_credentials_uoa_la_CPPFLAGS = \
+       $(AM_CPPFLAGS) \
+       -I$(top_srcdir) \
+       -DG_LOG_DOMAIN=\"module-credentials-uoa\" \
+       $(LIBACCOUNTS_GLIB_CFLAGS) \
+       $(LIBSIGNON_GLIB_CFLAGS) \
+       $(E_BACKEND_CFLAGS) \
+       $(JSON_GLIB_CFLAGS) \
+       $(CAMEL_CFLAGS) \
+       $(REST_CFLAGS) \
+       $(NULL)
+
+module_credentials_uoa_la_SOURCES = \
+       module-credentials-uoa.c \
+       e-signon-session-password.c \
+       e-signon-session-password.h \
+       $(NULL)
+
+module_credentials_uoa_la_LIBADD = \
+       $(top_builddir)/camel/libcamel-1.2.la \
+       $(top_builddir)/libebackend/libebackend-1.2.la \
+       $(top_builddir)/libedataserver/libedataserver-1.2.la \
+       $(LIBACCOUNTS_GLIB_LIBS) \
+       $(LIBSIGNON_GLIB_LIBS) \
+       $(E_BACKEND_LIBS) \
+       $(JSON_GLIB_LIBS) \
+       $(CAMEL_LIBS) \
+       $(REST_LIBS) \
+       $(NULL)
+
+module_credentials_uoa_la_LDFLAGS = \
+       -module -avoid-version $(NO_UNDEFINED) \
+       $(NULL)
+
 %.application: %.application.in
        $(AM_V_GEN) $(INTLTOOL_MERGE) --no-translations -x -u $< $@
 
diff --git a/modules/ubuntu-online-accounts/e-signon-session-password.c 
b/modules/ubuntu-online-accounts/e-signon-session-password.c
index 83d4bad..ff8c4fa 100644
--- a/modules/ubuntu-online-accounts/e-signon-session-password.c
+++ b/modules/ubuntu-online-accounts/e-signon-session-password.c
@@ -37,50 +37,37 @@ struct _ESignonSessionPasswordPrivate {
 };
 
 struct _AsyncContext {
-       ESourceAuthenticator *authenticator;
        SignonAuthSession *signon_auth_session;
        EAuthenticationSessionResult session_result;
        AgAuthData *ag_auth_data;
        GCancellable *cancellable;
+       GString *password;
 };
 
-/* Forward Declarations */
-static void    signon_session_password_msg
-                                       (EAuthenticationSession *session,
-                                        const gchar *format,
-                                        ...) G_GNUC_PRINTF (2, 3);
-static void    signon_session_password_process_cb
-                                       (GObject *source_object,
-                                        GAsyncResult *result,
-                                        gpointer user_data);
-
-G_DEFINE_DYNAMIC_TYPE (
-       ESignonSessionPassword,
-       e_signon_session_password,
-       E_TYPE_AUTHENTICATION_SESSION)
+G_DEFINE_DYNAMIC_TYPE (ESignonSessionPassword, e_signon_session_password, 
E_TYPE_SOURCE_CREDENTIALS_PROVIDER_IMPL)
 
 static void
 async_context_free (AsyncContext *async_context)
 {
-       if (async_context->authenticator != NULL)
-               g_object_unref (async_context->authenticator);
-
-       if (async_context->signon_auth_session != NULL)
-               g_object_unref (async_context->signon_auth_session);
+       g_clear_object (&async_context->signon_auth_session);
+       g_clear_object (&async_context->cancellable);
 
        if (async_context->ag_auth_data != NULL)
                ag_auth_data_unref (async_context->ag_auth_data);
 
-       if (async_context->cancellable != NULL)
-               g_object_unref (async_context->cancellable);
+       if (async_context->password) {
+               if (async_context->password->len)
+                       memset (async_context->password->str, 0, async_context->password->len);
+               g_string_free (async_context->password, TRUE);
+       }
 
        g_slice_free (AsyncContext, async_context);
 }
 
 static void
-signon_session_password_msg (EAuthenticationSession *session,
-                             const gchar *format,
-                             ...)
+e_signon_session_password_msg (ESource *source,
+                               const gchar *format,
+                              ...)
 {
        GString *buffer;
        const gchar *source_uid;
@@ -88,7 +75,7 @@ signon_session_password_msg (EAuthenticationSession *session,
 
        buffer = g_string_sized_new (256);
 
-       source_uid = e_authentication_session_get_source_uid (session);
+       source_uid = e_source_get_uid (source);
        g_string_append_printf (buffer, "AUTH (%s): ", source_uid);
 
        va_start (args, format);
@@ -104,34 +91,43 @@ static void
 signon_session_password_state_changed_cb (SignonAuthSession *signon_auth_session,
                                           gint state,
                                           const gchar *message,
-                                          EAuthenticationSession *session)
+                                          ESource *source)
 {
-       signon_session_password_msg (session, "(signond) %s", message);
+       e_signon_session_password_msg (source, "(signond) %s", message);
 }
 
 static AgAccountService *
-signon_session_password_new_account_service (EAuthenticationSession *session,
+signon_session_password_new_account_service (ESourceCredentialsProviderImpl *provider_impl,
                                              ESource *source,
                                              GError **error)
 {
        ESignonSessionPasswordPrivate *priv;
-       ESourceUoa *extension;
+       ESource *cred_source = NULL;
+       ESourceUoa *extension = NULL;
        AgAccountId account_id;
        AgAccount *ag_account = NULL;
        AgAccountService *ag_account_service;
        GList *list;
-       gboolean has_uoa_extension;
-       const gchar *extension_name;
 
-       priv = E_SIGNON_SESSION_PASSWORD_GET_PRIVATE (session);
+       priv = E_SIGNON_SESSION_PASSWORD_GET_PRIVATE (provider_impl);
+
+       if (e_source_has_extension (source, E_SOURCE_EXTENSION_UOA)) {
+               extension = e_source_get_extension (source, E_SOURCE_EXTENSION_UOA);
+       } else {
+               ESourceCredentialsProvider *provider;
+
+               provider = e_source_credentials_provider_impl_get_provider (provider_impl);
+
+               cred_source = e_source_credentials_provider_ref_credentials_source (provider, source);
+               if (cred_source && e_source_has_extension (cred_source, E_SOURCE_EXTENSION_UOA))
+                       extension = e_source_get_extension (cred_source, E_SOURCE_EXTENSION_UOA);
+       }
 
-       /* XXX The ESource should be a collection source with an
-        *     [Ubuntu Online Accounts] extension.  Verify this. */
-       extension_name = E_SOURCE_EXTENSION_UOA;
-       has_uoa_extension = e_source_has_extension (source, extension_name);
-       g_return_val_if_fail (has_uoa_extension, NULL);
+       if (!extension) {
+               g_clear_object (&cred_source);
+               return NULL;
+       }
 
-       extension = e_source_get_extension (source, extension_name);
        account_id = e_source_uoa_get_account_id (extension);
 
        ag_account = ag_manager_load_account (
@@ -157,60 +153,46 @@ signon_session_password_new_account_service (EAuthenticationSession *session,
        return ag_account_service;
 }
 
-static void
-signon_session_password_try_password_cb (GObject *source_object,
-                                         GAsyncResult *result,
-                                         gpointer user_data)
+static gboolean
+e_signon_session_password_can_process (ESourceCredentialsProviderImpl *provider_impl,
+                                      ESource *source)
 {
-       GSimpleAsyncResult *simple;
-       AsyncContext *async_context;
-       ESourceAuthenticationResult auth_result;
-       GVariantBuilder builder;
-       GVariant *session_data;
-       GError *error = NULL;
+       gboolean can_process;
 
-       simple = G_SIMPLE_ASYNC_RESULT (user_data);
-       async_context = g_simple_async_result_get_op_res_gpointer (simple);
+       g_return_val_if_fail (E_IS_SIGNON_SESSION_PASSWORD (provider_impl), FALSE);
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
 
-       auth_result = e_source_authenticator_try_password_finish (
-               E_SOURCE_AUTHENTICATOR (source_object), result, &error);
+       can_process = e_source_has_extension (source, E_SOURCE_EXTENSION_UOA);
+       if (!can_process) {
+               ESource *cred_source;
 
-       if (error != NULL) {
-               g_simple_async_result_take_error (simple, error);
-               g_simple_async_result_complete (simple);
-               goto exit;
-       }
+               cred_source = e_source_credentials_provider_ref_credentials_source (
+                       e_source_credentials_provider_impl_get_provider (provider_impl),
+                       source);
 
-       if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
-               async_context->session_result =
-                       E_AUTHENTICATION_SESSION_SUCCESS;
-               g_simple_async_result_complete (simple);
-               goto exit;
+               if (cred_source) {
+                       can_process = e_source_has_extension (cred_source, E_SOURCE_EXTENSION_UOA);
+                       g_clear_object (&cred_source);
+               }
        }
 
-       g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+       return can_process;
+}
 
-       /* Force the signon service to prompt for a password by adding
-        * SIGNON_POLICY_REQUEST_PASSWORD to the session data dictionary. */
-       g_variant_builder_add (
-               &builder, "{sv}", SIGNON_SESSION_DATA_UI_POLICY,
-               g_variant_new_int32 (SIGNON_POLICY_REQUEST_PASSWORD));
+static gboolean
+e_signon_session_password_can_store (ESourceCredentialsProviderImpl *provider_impl)
+{
+       g_return_val_if_fail (E_IS_SIGNON_SESSION_PASSWORD (provider_impl), FALSE);
 
-       /* This returns a floating reference. */
-       session_data = ag_auth_data_get_login_parameters (
-               async_context->ag_auth_data,
-               g_variant_builder_end (&builder));
+       return FALSE;
+}
 
-       signon_auth_session_process_async (
-               async_context->signon_auth_session,
-               session_data,
-               SIGNON_MECHANISM_PASSWORD,
-               async_context->cancellable,
-               signon_session_password_process_cb,
-               g_object_ref (simple));
+static gboolean
+e_signon_session_password_can_prompt (ESourceCredentialsProviderImpl *provider_impl)
+{
+       g_return_val_if_fail (E_IS_SIGNON_SESSION_PASSWORD (provider_impl), FALSE);
 
-exit:
-       g_object_unref (simple);
+       return FALSE;
 }
 
 static void
@@ -238,7 +220,6 @@ signon_session_password_process_cb (GObject *source_object,
 
        if (error != NULL) {
                g_simple_async_result_take_error (simple, error);
-               g_simple_async_result_complete (simple);
                goto exit;
        }
 
@@ -254,123 +235,52 @@ signon_session_password_process_cb (GObject *source_object,
                        simple, SIGNON_ERROR,
                        SIGNON_ERROR_MISSING_DATA,
                        _("Signon service did not return a secret"));
-               g_simple_async_result_complete (simple);
                goto exit;
        }
 
-       /* XXX It occurs to me now a GVariant might have been a better
-        *     choice for the password parameter in ESourceAuthenticator. */
-       string = g_string_new (g_variant_get_string (secret, NULL));
-
-       e_source_authenticator_try_password (
-               async_context->authenticator,
-               string,
-               async_context->cancellable,
-               signon_session_password_try_password_cb,
-               g_object_ref (simple));
+       async_context->password = g_string_new (g_variant_get_string (secret, NULL));
 
        g_string_free (string, TRUE);
        g_variant_unref (secret);
 
 exit:
+       g_simple_async_result_complete (simple);
        g_object_unref (simple);
 }
 
 static void
-signon_session_password_dispose (GObject *object)
-{
-       ESignonSessionPasswordPrivate *priv;
-
-       priv = E_SIGNON_SESSION_PASSWORD_GET_PRIVATE (object);
-
-       g_clear_object (&priv->ag_manager);
-
-       /* Chain up to parent's dispose() method. */
-       G_OBJECT_CLASS (e_signon_session_password_parent_class)->
-               dispose (object);
-}
-
-static EAuthenticationSessionResult
-signon_session_password_execute_sync (EAuthenticationSession *session,
-                                      GCancellable *cancellable,
-                                      GError **error)
-{
-       EAuthenticationSessionResult auth_result;
-       EAsyncClosure *async_closure;
-       GAsyncResult *async_result;
-
-       async_closure = e_async_closure_new ();
-
-       e_authentication_session_execute (
-               session, G_PRIORITY_DEFAULT, cancellable,
-               e_async_closure_callback, async_closure);
-
-       async_result = e_async_closure_wait (async_closure);
-
-       auth_result = e_authentication_session_execute_finish (
-               session, async_result, error);
-
-       e_async_closure_free (async_closure);
-
-       return auth_result;
-}
-
-static void
-signon_session_password_execute (EAuthenticationSession *session,
-                                 gint io_priority,
-                                 GCancellable *cancellable,
-                                 GAsyncReadyCallback callback,
-                                 gpointer user_data)
+e_signon_session_password_get (ESourceCredentialsProviderImpl *provider_impl,
+                              ESource *source,
+                              gint io_priority,
+                              GCancellable *cancellable,
+                              GAsyncReadyCallback callback,
+                              gpointer user_data)
 {
        GSimpleAsyncResult *simple;
        AsyncContext *async_context;
-       ESourceAuthenticator *authenticator;
-       ESourceRegistryServer *server;
-       ESource *source;
        AgAccountService *ag_account_service;
        AgAuthData *ag_auth_data;
        SignonAuthSession *signon_auth_session;
-       const gchar *source_uid;
        guint credentials_id;
        GError *error = NULL;
 
-       signon_session_password_msg (session, "Initiated");
-
-       authenticator = e_authentication_session_get_authenticator (session);
+       e_signon_session_password_msg (source, "Initiated");
 
        async_context = g_slice_new0 (AsyncContext);
-       async_context->authenticator = g_object_ref (authenticator);
 
        if (G_IS_CANCELLABLE (cancellable))
                async_context->cancellable = g_object_ref (cancellable);
 
        simple = g_simple_async_result_new (
-               G_OBJECT (session), callback, user_data,
-               signon_session_password_execute);
+               G_OBJECT (provider_impl), callback, user_data,
+               e_signon_session_password_get);
 
        g_simple_async_result_set_check_cancellable (simple, cancellable);
 
        g_simple_async_result_set_op_res_gpointer (
                simple, async_context, (GDestroyNotify) async_context_free);
 
-       server = e_authentication_session_get_server (session);
-       source_uid = e_authentication_session_get_source_uid (session);
-       source = e_source_registry_server_ref_source (server, source_uid);
-
-       if (source == NULL) {
-               g_simple_async_result_set_error (
-                       simple, G_IO_ERROR,
-                       G_IO_ERROR_NOT_FOUND,
-                       _("No such data source for UID '%s'"),
-                       source_uid);
-               g_simple_async_result_complete_in_idle (simple);
-               g_object_unref (simple);
-               return;
-       }
-
-       ag_account_service =
-               signon_session_password_new_account_service (
-               session, source, &error);
+       ag_account_service = signon_session_password_new_account_service (provider_impl, source, &error);
 
        g_object_unref (source);
 
@@ -407,7 +317,7 @@ signon_session_password_execute (EAuthenticationSession *session,
                g_signal_connect (
                        signon_auth_session, "state-changed",
                        G_CALLBACK (signon_session_password_state_changed_cb),
-                       session);
+                       source);
 
                /* Need to hold on to these in case of retries. */
                async_context->signon_auth_session = signon_auth_session;
@@ -435,74 +345,115 @@ signon_session_password_execute (EAuthenticationSession *session,
        g_object_unref (simple);
 }
 
-static EAuthenticationSessionResult
-signon_session_password_execute_finish (EAuthenticationSession *session,
-                                        GAsyncResult *result,
-                                        GError **error)
+static gboolean
+e_signon_session_password_get_finish (ESourceCredentialsProviderImpl *provider_impl,
+                                     GAsyncResult *result,
+                                     GString *out_password,
+                                     GError **error)
 {
        GSimpleAsyncResult *simple;
        AsyncContext *async_context;
-       EAuthenticationSessionResult session_result;
+       gboolean success;
 
        g_return_val_if_fail (
                g_simple_async_result_is_valid (
-               result, G_OBJECT (session),
-               signon_session_password_execute),
-               E_AUTHENTICATION_SESSION_DISMISSED);
+               result, G_OBJECT (provider_impl),
+               e_signon_session_password_get),
+               FALSE);
 
        simple = G_SIMPLE_ASYNC_RESULT (result);
        async_context = g_simple_async_result_get_op_res_gpointer (simple);
 
-       if (g_simple_async_result_propagate_error (simple, error))
-               session_result = E_AUTHENTICATION_SESSION_ERROR;
-       else
-               session_result = async_context->session_result;
-
-       switch (session_result) {
-               case E_AUTHENTICATION_SESSION_ERROR:
-                       if (error != NULL && *error != NULL)
-                               signon_session_password_msg (
-                                       session, "Complete (ERROR - %s)",
-                                       (*error)->message);
-                       else
-                               signon_session_password_msg (
-                                       session, "Complete (ERROR)");
-                       break;
-               case E_AUTHENTICATION_SESSION_SUCCESS:
-                       signon_session_password_msg (
-                               session, "Complete (SUCCESS)");
-                       break;
-               case E_AUTHENTICATION_SESSION_DISMISSED:
-                       signon_session_password_msg (
-                               session, "Complete (DISMISSED)");
-                       break;
-               default:
-                       g_warn_if_reached ();
+       if (g_simple_async_result_propagate_error (simple, error)) {
+               success = FALSE;
+       } else {
+               success = async_context->password != NULL;
+               if (success && out_password)
+                       g_string_assign (out_password, async_context->password->str);
        }
 
-       return session_result;
+       return success;
+}
+
+static gboolean
+e_signon_session_password_lookup_sync (ESourceCredentialsProviderImpl *provider_impl,
+                                      ESource *source,
+                                      GCancellable *cancellable,
+                                      ENamedParameters **out_credentials,
+                                      GError **error)
+{
+       EAsyncClosure *async_closure;
+       GAsyncResult *async_result;
+       gboolean success;
+       GString *password;
+
+       g_return_val_if_fail (E_IS_SOURCE (source), FALSE);
+       g_return_val_if_fail (out_credentials != NULL, FALSE);
+
+       async_closure = e_async_closure_new ();
+
+       e_signon_session_password_get (provider_impl, source,
+               G_PRIORITY_DEFAULT, cancellable,
+               e_async_closure_callback, async_closure);
+
+       async_result = e_async_closure_wait (async_closure);
+
+       password = g_string_new ("");
+
+       success = e_signon_session_password_get_finish (provider_impl, async_result, password, error);
+       if (success) {
+               *out_credentials = e_named_parameters_new ();
+               e_named_parameters_set (*out_credentials, E_SOURCE_CREDENTIAL_PASSWORD, password->str);
+       }
+
+       if (password->str)
+               memset (password->str, 0, password->len);
+       g_string_free (password, TRUE);
+
+       e_async_closure_free (async_closure);
+
+       if (success) {
+               e_signon_session_password_msg (source, "Complete (SUCCESS)");
+       } else if (error && *error) {
+               e_signon_session_password_msg (source, "Complete (ERROR - %s)", (*error)->message);
+       } else {
+               e_signon_session_password_msg (source, "Complete (ERROR)");
+       }
+
+
+       return success;
+}
+
+static void
+signon_session_password_dispose (GObject *object)
+{
+       ESignonSessionPasswordPrivate *priv;
+
+       priv = E_SIGNON_SESSION_PASSWORD_GET_PRIVATE (object);
+
+       g_clear_object (&priv->ag_manager);
+
+       /* Chain up to parent's dispose() method. */
+       G_OBJECT_CLASS (e_signon_session_password_parent_class)->
+               dispose (object);
 }
 
 static void
 e_signon_session_password_class_init (ESignonSessionPasswordClass *class)
 {
        GObjectClass *object_class;
-       EAuthenticationSessionClass *authentication_session_class;
+       ESourceCredentialsProviderImplClass *provider_impl_class;
 
-       g_type_class_add_private (
-               class, sizeof (ESignonSessionPasswordPrivate));
+       g_type_class_add_private (class, sizeof (ESignonSessionPasswordPrivate));
 
        object_class = G_OBJECT_CLASS (class);
        object_class->dispose = signon_session_password_dispose;
 
-       authentication_session_class =
-               E_AUTHENTICATION_SESSION_CLASS (class);
-       authentication_session_class->execute_sync =
-               signon_session_password_execute_sync;
-       authentication_session_class->execute =
-               signon_session_password_execute;
-       authentication_session_class->execute_finish =
-               signon_session_password_execute_finish;
+       provider_impl_class = E_SOURCE_CREDENTIALS_PROVIDER_IMPL_CLASS (class);
+       provider_impl_class->can_process = e_signon_session_password_can_process;
+       provider_impl_class->can_store = e_signon_session_password_can_store;
+       provider_impl_class->can_prompt = e_signon_session_password_can_prompt;
+       provider_impl_class->lookup_sync = e_signon_session_password_lookup_sync;
 }
 
 static void
diff --git a/modules/ubuntu-online-accounts/e-signon-session-password.h 
b/modules/ubuntu-online-accounts/e-signon-session-password.h
index fec7179..89d1dba 100644
--- a/modules/ubuntu-online-accounts/e-signon-session-password.h
+++ b/modules/ubuntu-online-accounts/e-signon-session-password.h
@@ -18,7 +18,7 @@
 #ifndef E_SIGNON_SESSION_PASSWORD_H
 #define E_SIGNON_SESSION_PASSWORD_H
 
-#include <libebackend/libebackend.h>
+#include <libedataserver/libedataserver.h>
 
 /* Standard GObject macros */
 #define E_TYPE_SIGNON_SESSION_PASSWORD \
@@ -46,12 +46,12 @@ typedef struct _ESignonSessionPasswordClass ESignonSessionPasswordClass;
 typedef struct _ESignonSessionPasswordPrivate ESignonSessionPasswordPrivate;
 
 struct _ESignonSessionPassword {
-       EAuthenticationSession parent;
+       ESourceCredentialsProviderImpl parent;
        ESignonSessionPasswordPrivate *priv;
 };
 
 struct _ESignonSessionPasswordClass {
-       EAuthenticationSessionClass parent_class;
+       ESourceCredentialsProviderImplClass parent_class;
 };
 
 GType          e_signon_session_password_get_type
diff --git a/modules/ubuntu-online-accounts/module-credentials-uoa.c 
b/modules/ubuntu-online-accounts/module-credentials-uoa.c
new file mode 100644
index 0000000..30c2a46
--- /dev/null
+++ b/modules/ubuntu-online-accounts/module-credentials-uoa.c
@@ -0,0 +1,37 @@
+/*
+ * module-credentials-uoa.c
+ *
+ * This library is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "e-signon-session-password.h"
+
+/* Module Entry Points */
+void e_module_load (GTypeModule *type_module);
+void e_module_unload (GTypeModule *type_module);
+
+G_MODULE_EXPORT void
+e_module_load (GTypeModule *type_module)
+{
+       e_signon_session_password_type_register (type_module);
+}
+
+G_MODULE_EXPORT void
+e_module_unload (GTypeModule *type_module)
+{
+}
diff --git a/modules/ubuntu-online-accounts/module-ubuntu-online-accounts.c 
b/modules/ubuntu-online-accounts/module-ubuntu-online-accounts.c
index 4caec66..6e5577a 100644
--- a/modules/ubuntu-online-accounts/module-ubuntu-online-accounts.c
+++ b/modules/ubuntu-online-accounts/module-ubuntu-online-accounts.c
@@ -21,7 +21,6 @@
 #include <libaccounts-glib/accounts-glib.h>
 
 #include "uoa-utils.h"
-#include "e-signon-session-password.h"
 
 /* Standard GObject macros */
 #define E_TYPE_UBUNTU_ONLINE_ACCOUNTS \
@@ -375,11 +374,6 @@ ubuntu_online_accounts_config_collection (EUbuntuOnlineAccounts *extension,
        e_server_side_source_set_removable (
                E_SERVER_SIDE_SOURCE (source), FALSE);
 
-       /* Obtain passwords from the signond service. */
-       e_server_side_source_set_auth_session_type (
-               E_SERVER_SIDE_SOURCE (source),
-               E_TYPE_SIGNON_SESSION_PASSWORD);
-
        if (supports_oauth2) {
                /* This module provides OAuth 2.0 support to the collection.
                 * Note, children of the collection source will automatically
@@ -1139,7 +1133,6 @@ G_MODULE_EXPORT void
 e_module_load (GTypeModule *type_module)
 {
        e_ubuntu_online_accounts_register_type (type_module);
-       e_signon_session_password_type_register (type_module);
 }
 
 G_MODULE_EXPORT void
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 8c78a8d..9f8ff65 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -173,8 +173,6 @@ camel/providers/smtp/camel-smtp-transport.c
 data/org.gnome.evolution-data-server.addressbook.gschema.xml.in
 data/org.gnome.evolution-data-server.calendar.gschema.xml.in
 data/org.gnome.evolution.shell.network-config.gschema.xml.in
-libebackend/e-authentication-mediator.c
-libebackend/e-authentication-session.c
 libebackend/e-backend.c
 libebackend/e-collection-backend.c
 libebackend/e-data-factory.c
@@ -184,13 +182,17 @@ libebackend/e-subprocess-factory.c
 libebackend/e-user-prompter-server.c
 libedataserver/e-categories.c
 libedataserver/e-client.c
-libedataserver/e-source-authenticator.c
 libedataserver/e-source.c
+libedataserver/e-source-credentials-provider-impl.c
+libedataserver/e-source-credentials-provider-impl-password.c
 libedataserver/e-source-mail-signature.c
 libedataserver/e-source-proxy.c
 libedataserver/e-source-registry.c
 libedataserver/e-source-webdav.c
 libedataserver/e-time-utils.c
+libedataserverui/e-credentials-prompter.c
+libedataserverui/e-credentials-prompter-impl-password.c
+libedataserverui/e-trust-prompt.c
 modules/gnome-online-accounts/e-goa-password-based.c
 modules/gnome-online-accounts/goaewsclient.c
 modules/gnome-online-accounts/module-gnome-online-accounts.c
diff --git a/private/org.gnome.evolution.dataserver.AddressBook.xml 
b/private/org.gnome.evolution.dataserver.AddressBook.xml
index f8ff126..b91f82b 100644
--- a/private/org.gnome.evolution.dataserver.AddressBook.xml
+++ b/private/org.gnome.evolution.dataserver.AddressBook.xml
@@ -28,6 +28,10 @@
     <arg name="error_message" type="s"/>
   </signal>
 
+  <method name="RetrieveProperties">
+    <arg name="properties" direction="out" type="as"/>
+  </method>
+
   <method name="Open">
     <arg name="properties" direction="out" type="as"/>
   </method>
diff --git a/private/org.gnome.evolution.dataserver.Calendar.xml 
b/private/org.gnome.evolution.dataserver.Calendar.xml
index 8d76194..5c21327 100644
--- a/private/org.gnome.evolution.dataserver.Calendar.xml
+++ b/private/org.gnome.evolution.dataserver.Calendar.xml
@@ -32,6 +32,10 @@
     <arg name="ics_objects" type="as"/>
   </signal>
 
+  <method name="RetrieveProperties">
+    <arg name="properties" direction="out" type="as"/>
+  </method>
+
   <method name="Open">
     <arg name="properties" direction="out" type="as"/>
   </method>
diff --git a/private/org.gnome.evolution.dataserver.Source.xml 
b/private/org.gnome.evolution.dataserver.Source.xml
index dc3f0f5..cf31fa2 100644
--- a/private/org.gnome.evolution.dataserver.Source.xml
+++ b/private/org.gnome.evolution.dataserver.Source.xml
@@ -14,14 +14,105 @@
   <property name="UID" type="s" access="read"/>
   <!-- Data: Raw key file data describing the source. -->
   <property name="Data" type="s" access="read"/>
+  <!-- ConnectionStatus: Current ESourceConnectionStatus of the source. @since: 3.14 -->
+  <property name="ConnectionStatus" type="s" access="readwrite"/>
 
   <!--
-      AllowAuthPrompt:
+      CredentialsRequired:
+      @reason: one of the ESourceCredentialsReason values
+      @certificate_pem: either an empty string or a PEM-encoded certificate
+                        being used for the SSL connection
+      @certificate_errors: a GTlsCertificateFlags bit-or of certificate errors
+      @dbus_error_name: a GDBus' error name for a failed authentication
+      @dbus_error_message: actual error message corresponding to @dbus_error_name
+      @since: 3.14
+
+      Emitted, when the source requires credentials, like for login, to be
+      able to connect to its destination. The client side may listen to it
+      to let a user know that the credentials are required, eventually ask
+      for the credentials (password) straight away.
+      The ConnectionStatus property changes accordingly, when one of
+      the listeners will provide the credentials using Authenticate method.
+      The reason argument says why the credentials are required.
+
+      The value E_SOURCE_CREDENTIALS_REASON_SSL_FAILED indicates a failed
+      certificate check on a secured connection, then the certificate_pem and
+      certificate_errors are populated with the actual certificate being used
+      and what failed with it. Otherwise these two arguments are meaningless.
+      The error argument can contain a text description of the certificate_errors too.
+
+      The value E_SOURCE_CREDENTIALS_REASON_ERROR indicates a failure
+      on the server side, other than rejected credentials or failed SSL
+      checks. In this case the 'error' argument holds a text description of
+      the error. The 'error' argument is meaningless or optional in other cases.
+  -->
+  <signal name="CredentialsRequired">
+    <arg name="reason" direction="in" type="s"/>
+    <arg name="certificate_pem" direction="in" type="s"/>
+    <arg name="certificate_errors" direction="in" type="s"/>
+    <arg name="dbus_error_name" direction="in" type="s"/>
+    <arg name="dbus_error_message" direction="in" type="s"/>
+  </signal>
+
+  <!--
+      InvokeCredentialsRequired:
+      @since: 3.14
+
+      Invokes CredentialsRequired signal on the server side, thus it can
+      be received by all clients.
+  -->
+  <method name="InvokeCredentialsRequired">
+    <arg name="reason" direction="in" type="s"/>
+    <arg name="certificate_pem" direction="in" type="s"/>
+    <arg name="certificate_errors" direction="in" type="s"/>
+    <arg name="dbus_error_name" direction="in" type="s"/>
+    <arg name="dbus_error_message" direction="in" type="s"/>
+  </method>
+
+  <!--
+      GetLastCredentialsRequiredArguments:
+      @reason: (out): The 'reason' argument used in the last call of CredentialsRequired()
+      @certificate_pem: (out): The 'certificate_pem' argument used in the last call of CredentialsRequired()
+      @certificate_errors: (out): The 'certificate_errors' argument used in the last call of 
CredentialsRequired()
+      @dbus_error_name: (out): The 'dbus_error_name' argument used in the last call of CredentialsRequired()
+      @dbus_error_message: (out): The 'dbus_error_message' argument used in the last call of 
CredentialsRequired()
+      @since: 3.14
+
+      Returns tha last arguments used to the call of CredentialsRequired().
+      The values are automatically unset with the Authenticate() call.
+  -->
+  <method name="GetLastCredentialsRequiredArguments">
+    <arg name="reason" direction="out" type="s"/>
+    <arg name="certificate_pem" direction="out" type="s"/>
+    <arg name="certificate_errors" direction="out" type="s"/>
+    <arg name="dbus_error_name" direction="out" type="s"/>
+    <arg name="dbus_error_message" direction="out" type="s"/>
+  </method>
+
+  <!--
+      Authenticate:
+      @credentials: provided credentials, in a GKeyFile format
+      @since: 3.14
 
-      If the user declines to provide a secret when prompted, further
-      authentication prompts are inhibited until this method is called.
+      This is a response method for a signal CredentialsRequired, when
+      the credentials had been obtained from a user. The @credentials is
+      an array of strings suitable for ECredentials structure.
   -->
-  <method name="AllowAuthPrompt"/>
+  <signal name="Authenticate">
+    <arg name="credentials" direction="in" type="as"/>
+  </signal>
+
+  <!--
+      InvokeAuthenticate:
+      @since: 3.14
+
+      Invokes Authenticate signal on the server side, thus it can
+      be received by all clients (and served by backends).
+  -->
+  <method name="InvokeAuthenticate">
+    <arg name="credentials" direction="in" type="as"/>
+  </method>
+
 </interface>
 
 <!--
diff --git a/private/org.gnome.evolution.dataserver.SourceManager.xml 
b/private/org.gnome.evolution.dataserver.SourceManager.xml
index ac58f97..3c5fad8 100644
--- a/private/org.gnome.evolution.dataserver.SourceManager.xml
+++ b/private/org.gnome.evolution.dataserver.SourceManager.xml
@@ -11,40 +11,6 @@
 -->
 <interface name="org.gnome.evolution.dataserver.SourceManager">
   <!--
-      AllowAuthPromptAll:
-      @since: 3.8
-
-      This method is equivalent to calling AllowAuthPrompt() on each
-      managed object, but does so in a single method invocation.
-  -->
-  <method name="AllowAuthPromptAll"/>
-
-  <!--
-      Authenticate:
-      @uid: Unique identifier for the authenticating source
-      @prompt_title: The title of the prompt
-      @prompt_message: The prompt message for the user
-      @prompt_description: The detailed description of the prompt
-      @object_path: Object path of a new authentication session
-
-      Initiates a new authentication session at the returned object
-      path.  The client should prepare to receive Response signals
-      from the Authenticator interface at that object path, then
-      call the interface's Ready method.
-
-      The @prompt_title, @prompt_message and @prompt_description
-      arguments are used to construct an authentication prompt if
-      necessary.  (See #GcrPrompt for details.)
-  -->
-  <method name="Authenticate">
-    <arg name="uid" direction="in" type="s"/>
-    <arg name="prompt_title" direction="in" type="s"/>
-    <arg name="prompt_message" direction="in" type="s"/>
-    <arg name="prompt_description" direction="in" type="s"/>
-    <arg name="object_path" direction="out" type="s"/>
-  </method>
-
-  <!--
       CreateSources:
       @array: An array of "uid" and "data" pairs
 
diff --git a/tests/book-migration/setup-migration-test.c b/tests/book-migration/setup-migration-test.c
index 2350da7..4cfcc36 100644
--- a/tests/book-migration/setup-migration-test.c
+++ b/tests/book-migration/setup-migration-test.c
@@ -130,7 +130,7 @@ source_added (ESourceRegistry *registry,
 
        /* Open the address book */
 #if EDS_CHECK_VERSION(3,8,0)
-       added_data->book = (EBookClient *) e_book_client_connect_sync (source, NULL, &error);
+       added_data->book = (EBookClient *) e_book_client_connect_sync (source, 30, NULL, &error);
 #else
        /* With 3.6 it's a bit more tricky */
        added_data->book = e_book_client_new (source, &error);
diff --git a/tests/libebook/client/test-book-client-self.c b/tests/libebook/client/test-book-client-self.c
index 5c2e2da..8c7f438 100644
--- a/tests/libebook/client/test-book-client-self.c
+++ b/tests/libebook/client/test-book-client-self.c
@@ -56,7 +56,7 @@ test_set_self (ETestServerFixture *fixture,
 
        /* Open the system addressbook */
        source = e_source_registry_ref_builtin_address_book (fixture->registry);
-       client = (EBookClient *) e_book_client_connect_sync (source, NULL, &error);
+       client = (EBookClient *) e_book_client_connect_sync (source, 30, NULL, &error);
        g_object_unref (source);
        if (!client)
                g_error ("Error connecting to system addressbook: %s", error->message);
diff --git a/tests/libebook/client/test-book-client-view-operations.c 
b/tests/libebook/client/test-book-client-view-operations.c
index baf16cc..4e61469 100644
--- a/tests/libebook/client/test-book-client-view-operations.c
+++ b/tests/libebook/client/test-book-client-view-operations.c
@@ -198,7 +198,7 @@ test_view_thread_async (ThreadData *data)
        if (data->closure->type == E_TEST_SERVER_DIRECT_ADDRESS_BOOK) {
                /* There is no Async API to open a direct book for now, let's stick with the sync API
                 */
-               data->client = (EBookClient *) e_book_client_connect_direct_sync (registry, source, NULL, 
&error);
+               data->client = (EBookClient *) e_book_client_connect_direct_sync (registry, source, 30, NULL, 
&error);
 
                if (!data->client)
                        g_error ("Unable to create EBookClient for uid '%s': %s", data->book_uid, 
error->message);
@@ -208,7 +208,7 @@ test_view_thread_async (ThreadData *data)
 
        } else {
                /* Connect asynchronously */
-               e_book_client_connect (source, NULL, connect_ready, data);
+               e_book_client_connect (source, 30, NULL, connect_ready, data);
        }
 
        g_main_loop_run (data->loop);
@@ -280,9 +280,9 @@ test_view_thread_sync (ThreadData *data)
                g_error ("Unable to fetch source uid '%s' from the registry", data->book_uid);
 
        if (data->closure->type == E_TEST_SERVER_DIRECT_ADDRESS_BOOK)
-               data->client = (EBookClient *) e_book_client_connect_direct_sync (registry, source, NULL, 
&error);
+               data->client = (EBookClient *) e_book_client_connect_direct_sync (registry, source, 30, NULL, 
&error);
        else
-               data->client = (EBookClient *) e_book_client_connect_sync (source, NULL, &error);
+               data->client = (EBookClient *) e_book_client_connect_sync (source, 30, NULL, &error);
 
        if (!data->client)
                g_error ("Unable to create EBookClient for uid '%s': %s", data->book_uid, error->message);
diff --git a/tests/test-server-utils/e-test-server-utils.c b/tests/test-server-utils/e-test-server-utils.c
index 7417da1..34a5808 100644
--- a/tests/test-server-utils/e-test-server-utils.c
+++ b/tests/test-server-utils/e-test-server-utils.c
@@ -358,19 +358,19 @@ e_test_server_utils_source_added (ESourceRegistry *registry,
 
                if (pair->closure->type == E_TEST_SERVER_DIRECT_ADDRESS_BOOK) {
                        if (pair->closure->use_async_connect)
-                               e_book_client_connect_direct (source, NULL, e_test_server_utils_client_ready, 
pair);
+                               e_book_client_connect_direct (source, 30, NULL, 
e_test_server_utils_client_ready, pair);
                        else
                                pair->fixture->service.book_client = (EBookClient *)
                                        e_book_client_connect_direct_sync (
                                                pair->fixture->registry,
-                                               source, NULL, &error);
+                                               source, 30, NULL, &error);
                } else {
 
                        if (pair->closure->use_async_connect)
-                               e_book_client_connect (source, NULL, e_test_server_utils_client_ready, pair);
+                               e_book_client_connect (source, 30, NULL, e_test_server_utils_client_ready, 
pair);
                        else
                                pair->fixture->service.book_client = (EBookClient *)
-                                       e_book_client_connect_sync (source, NULL, &error);
+                                       e_book_client_connect_sync (source, 30, NULL, &error);
                }
 
                if (!pair->closure->use_async_connect &&
@@ -395,7 +395,7 @@ e_test_server_utils_source_added (ESourceRegistry *registry,
 
                if (pair->closure->use_async_connect) {
                        e_cal_client_connect (
-                               source, pair->closure->calendar_source_type,
+                               source, pair->closure->calendar_source_type, 30,
                                NULL, e_test_server_utils_client_ready, pair);
 
                } else {
@@ -403,7 +403,7 @@ e_test_server_utils_source_added (ESourceRegistry *registry,
                        pair->fixture->service.calendar_client = (ECalClient *)
                                e_cal_client_connect_sync (
                                        source,
-                                       pair->closure->calendar_source_type, NULL, &error);
+                                       pair->closure->calendar_source_type, 30, NULL, &error);
                        if (!pair->fixture->service.calendar_client)
                                g_error ("Unable to create the test calendar: %s", error->message);
                }


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