diff options
author | Milan Crha <mcrha@redhat.com> | 2015-02-02 14:44:05 +0100 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2015-02-02 14:44:05 +0100 |
commit | 884fb8d872787d9c9e8132d4cfca47f275d9da3e (patch) | |
tree | 13875694627f5539660d776a520cff230632acfd /addressbook | |
parent | a83cc09fc20edb2401f1e08d9d7b9f2eca408641 (diff) | |
download | evolution-data-server-884fb8d872787d9c9e8132d4cfca47f275d9da3e.tar.gz |
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.
Diffstat (limited to 'addressbook')
-rw-r--r-- | addressbook/backends/file/e-book-backend-file.c | 3 | ||||
-rw-r--r-- | addressbook/backends/google/e-book-backend-google.c | 163 | ||||
-rw-r--r-- | addressbook/backends/ldap/e-book-backend-ldap.c | 120 | ||||
-rw-r--r-- | addressbook/backends/webdav/e-book-backend-webdav.c | 180 | ||||
-rw-r--r-- | addressbook/libebook/e-book-client.c | 101 | ||||
-rw-r--r-- | addressbook/libebook/e-book-client.h | 4 | ||||
-rw-r--r-- | addressbook/libedata-book/e-book-backend.c | 19 | ||||
-rw-r--r-- | addressbook/libedata-book/e-data-book.c | 67 |
8 files changed, 453 insertions, 204 deletions
diff --git a/addressbook/backends/file/e-book-backend-file.c b/addressbook/backends/file/e-book-backend-file.c index 8f8f085a6..b0dbe79b9 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 19d1ac784..7f4d29bc0 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 52ce591db..559ebbfd5 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 4402a9e14..5f130a5d7 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 ebd1a2cac..609b0a2d7 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 feb3df815..3a557f98a 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 acc6e67e0..51cc2f4e3 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 4d66ec715..165fcda74 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); |