2 * e-authentication-session.c
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
20 * SECTION: e-authentication-session
21 * @include: libebackend/libebackend.h
22 * @short_description: Centralized authentication management
24 * #EAuthenticationSession provides centralized password management and
25 * password prompting for all clients of the registry D-Bus service.
27 * An #EAuthenticationSession is created within the registry D-Bus service
28 * when the service receives a request to authenticate some data source.
29 * Clients can issue requests by calling e_source_registry_authenticate().
30 * Requests can also come from any #ECollectionBackend running within the
33 * An #EAuthenticationSession requires some object implementing the
34 * #ESourceAuthenticator interface to verify stored or user-provided
35 * passwords. #EAuthenticationMediator is used for client-issued
36 * authentication requests. Custom collection backends derived from
37 * #ECollectionBackend usually implement the #ESourceAuthenticator
38 * interface themselves.
40 * The #EAuthenticationSession is then handed to #ESourceRegistryServer
41 * through e_source_registry_server_authenticate() where it waits in line
42 * behind other previously added authentication sessions. When its turn
43 * comes, the server calls e_authentication_session_execute() to begin
44 * the interactive authentication session.
47 #include "e-authentication-session.h"
49 /* XXX Yeah, yeah... */
50 #define GCR_API_SUBJECT_TO_CHANGE
54 #include <glib/gi18n-lib.h>
55 #include <gcr/gcr-base.h>
56 #include <libsecret/secret.h>
58 /* Private D-Bus classes. */
59 #include <e-dbus-authenticator.h>
61 #include <libebackend/e-authentication-mediator.h>
62 #include <libebackend/e-backend-enumtypes.h>
63 #include <libebackend/e-server-side-source.h>
64 #include <libebackend/e-source-registry-server.h>
66 #define E_AUTHENTICATION_SESSION_GET_PRIVATE(obj) \
67 (G_TYPE_INSTANCE_GET_PRIVATE \
68 ((obj), E_TYPE_AUTHENTICATION_SESSION, EAuthenticationSessionPrivate))
70 /* Wait forever for a system prompt. */
71 #define SYSTEM_PROMPT_TIMEOUT (-1)
73 #define KEYRING_ITEM_ATTRIBUTE_NAME "e-source-uid"
74 #define KEYRING_ITEM_DISPLAY_FORMAT "Evolution Data Source %s"
76 typedef struct _AsyncContext AsyncContext;
78 struct _EAuthenticationSessionPrivate {
79 ESourceRegistryServer *server;
80 ESourceAuthenticator *authenticator;
83 /* These are for configuring system prompts. */
86 gchar *prompt_message;
87 gchar *prompt_description;
90 struct _AsyncContext {
91 EAuthenticationSessionResult auth_result;
99 PROP_PROMPT_DESCRIPTION,
106 static SecretSchema schema = {
107 "org.gnome.Evolution.Data.Source",
108 SECRET_SCHEMA_DONT_MATCH_NAME,
110 { KEYRING_ITEM_ATTRIBUTE_NAME,
111 SECRET_SCHEMA_ATTRIBUTE_STRING },
116 /* Forward Declarations */
117 static void authentication_session_msg
118 (EAuthenticationSession *session,
120 ...) G_GNUC_PRINTF (2, 3);
123 EAuthenticationSession,
124 e_authentication_session,
128 async_context_free (AsyncContext *async_context)
130 g_free (async_context->password);
131 g_slice_free (AsyncContext, async_context);
135 authentication_session_msg (EAuthenticationSession *session,
142 buffer = g_string_sized_new (256);
144 g_string_append_printf (
145 buffer, "AUTH (%s): ",
146 session->priv->source_uid);
148 va_start (args, format);
149 g_string_append_vprintf (buffer, format, args);
152 g_print ("%s\n", buffer->str);
154 g_string_free (buffer, TRUE);
158 authentication_session_set_authenticator (EAuthenticationSession *session,
159 ESourceAuthenticator *authenticator)
161 g_return_if_fail (E_IS_SOURCE_AUTHENTICATOR (authenticator));
162 g_return_if_fail (session->priv->authenticator == NULL);
164 session->priv->authenticator = g_object_ref (authenticator);
168 authentication_session_set_server (EAuthenticationSession *session,
169 ESourceRegistryServer *server)
171 g_return_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server));
172 g_return_if_fail (session->priv->server == NULL);
174 session->priv->server = g_object_ref (server);
178 authentication_session_set_source_uid (EAuthenticationSession *session,
179 const gchar *source_uid)
181 g_return_if_fail (source_uid != NULL);
182 g_return_if_fail (session->priv->source_uid == NULL);
184 session->priv->source_uid = g_strdup (source_uid);
188 authentication_session_set_property (GObject *object,
193 switch (property_id) {
194 case PROP_AUTHENTICATOR:
195 authentication_session_set_authenticator (
196 E_AUTHENTICATION_SESSION (object),
197 g_value_get_object (value));
200 case PROP_PROMPT_DESCRIPTION:
201 e_authentication_session_set_prompt_description (
202 E_AUTHENTICATION_SESSION (object),
203 g_value_get_string (value));
206 case PROP_PROMPT_MESSAGE:
207 e_authentication_session_set_prompt_message (
208 E_AUTHENTICATION_SESSION (object),
209 g_value_get_string (value));
212 case PROP_PROMPT_TITLE:
213 e_authentication_session_set_prompt_title (
214 E_AUTHENTICATION_SESSION (object),
215 g_value_get_string (value));
219 authentication_session_set_server (
220 E_AUTHENTICATION_SESSION (object),
221 g_value_get_object (value));
224 case PROP_SOURCE_UID:
225 authentication_session_set_source_uid (
226 E_AUTHENTICATION_SESSION (object),
227 g_value_get_string (value));
231 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
235 authentication_session_get_property (GObject *object,
240 switch (property_id) {
241 case PROP_AUTHENTICATOR:
244 e_authentication_session_get_authenticator (
245 E_AUTHENTICATION_SESSION (object)));
248 case PROP_PROMPT_DESCRIPTION:
249 g_value_take_string (
251 e_authentication_session_dup_prompt_description (
252 E_AUTHENTICATION_SESSION (object)));
255 case PROP_PROMPT_MESSAGE:
256 g_value_take_string (
258 e_authentication_session_dup_prompt_message (
259 E_AUTHENTICATION_SESSION (object)));
262 case PROP_PROMPT_TITLE:
263 g_value_take_string (
265 e_authentication_session_dup_prompt_title (
266 E_AUTHENTICATION_SESSION (object)));
272 e_authentication_session_get_server (
273 E_AUTHENTICATION_SESSION (object)));
276 case PROP_SOURCE_UID:
279 e_authentication_session_get_source_uid (
280 E_AUTHENTICATION_SESSION (object)));
284 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
288 authentication_session_dispose (GObject *object)
290 EAuthenticationSessionPrivate *priv;
292 priv = E_AUTHENTICATION_SESSION_GET_PRIVATE (object);
294 if (priv->server != NULL) {
295 g_object_unref (priv->server);
299 if (priv->authenticator != NULL) {
300 g_object_unref (priv->authenticator);
301 priv->authenticator = NULL;
304 /* Chain up to parent's dispose() method. */
305 G_OBJECT_CLASS (e_authentication_session_parent_class)->
310 authentication_session_finalize (GObject *object)
312 EAuthenticationSessionPrivate *priv;
314 priv = E_AUTHENTICATION_SESSION_GET_PRIVATE (object);
316 g_mutex_clear (&priv->property_lock);
318 g_free (priv->source_uid);
319 g_free (priv->prompt_title);
320 g_free (priv->prompt_message);
321 g_free (priv->prompt_description);
323 /* Chain up to parent's finalize() method. */
324 G_OBJECT_CLASS (e_authentication_session_parent_class)->
329 authentication_session_constructed (GObject *object)
331 EAuthenticationSession *session;
332 ESourceAuthenticator *authenticator;
333 ESourceRegistryServer *server;
335 const gchar *source_uid;
337 session = E_AUTHENTICATION_SESSION (object);
339 /* Chain up to parent's constructed() method. */
340 G_OBJECT_CLASS (e_authentication_session_parent_class)->
341 constructed (object);
343 /* If the server knows about the data source UID we've been
344 * given, then we can auto-configure our own prompt strings. */
346 server = e_authentication_session_get_server (session);
347 source_uid = e_authentication_session_get_source_uid (session);
348 authenticator = e_authentication_session_get_authenticator (session);
350 source = e_source_registry_server_ref_source (server, source_uid);
351 if (source != NULL) {
352 gchar *prompt_title = NULL;
353 gchar *prompt_message = NULL;
354 gchar *prompt_description = NULL;
356 e_source_authenticator_get_prompt_strings (
357 authenticator, source,
360 &prompt_description);
364 "prompt-title", prompt_title,
365 "prompt-message", prompt_message,
366 "prompt-description", prompt_description,
369 g_free (prompt_title);
370 g_free (prompt_message);
371 g_free (prompt_description);
373 g_object_unref (source);
377 /* Helper for authentication_session_execute() */
379 authentication_session_execute_thread (GSimpleAsyncResult *simple,
381 GCancellable *cancellable)
383 AsyncContext *async_context;
384 GError *error = NULL;
386 async_context = g_simple_async_result_get_op_res_gpointer (simple);
388 async_context->auth_result =
389 e_authentication_session_execute_sync (
390 E_AUTHENTICATION_SESSION (object),
391 cancellable, &error);
394 g_simple_async_result_take_error (simple, error);
397 static EAuthenticationSessionResult
398 authentication_session_execute_sync (EAuthenticationSession *session,
399 GCancellable *cancellable,
402 ESourceAuthenticator *authenticator;
403 EAuthenticationSessionResult session_result;
404 ESourceAuthenticationResult auth_result;
405 ESourceRegistryServer *server;
408 GString *password_string;
409 gboolean allow_auth_prompt;
411 const gchar *source_uid;
412 const gchar *prompt_password;
413 gchar *stored_password = NULL;
415 GError *local_error = NULL;
417 /* XXX I moved the execute() operation into a class method thinking
418 * we might someday want to subclass EAuthenticationSession and
419 * override this method to make it behave differently.
421 * It would be a little premature to do this now, but we might
422 * also want to use the basic algorithm here as a template and
423 * turn the password lookup/delete/store operations into class
424 * methods that could also be overridden. I reserved adequate
425 * space in the class struct for this should the need arise.
427 * For now though we'll keep it simple. I don't want to over-
428 * engineer this too much in trying to make it future-proof.
431 authentication_session_msg (session, "Initiated");
433 server = e_authentication_session_get_server (session);
434 source_uid = e_authentication_session_get_source_uid (session);
435 authenticator = e_authentication_session_get_authenticator (session);
437 success = e_authentication_session_lookup_password_sync (
438 session, cancellable, &stored_password, error);
441 session_result = E_AUTHENTICATION_SESSION_ERROR;
445 auth_result = E_SOURCE_AUTHENTICATION_REJECTED;
447 /* If we found a stored password, signal the client without
448 * interrupting the user. Note, if the client responds with
449 * REJECTED, we'll have to interrupt the user after all. */
450 if (stored_password != NULL) {
451 password_string = g_string_new (stored_password);
453 auth_result = e_source_authenticator_try_password_sync (
454 authenticator, password_string, cancellable, error);
456 g_string_free (password_string, TRUE);
457 password_string = NULL;
459 g_free (stored_password);
460 stored_password = NULL;
463 if (auth_result == E_SOURCE_AUTHENTICATION_ERROR) {
464 session_result = E_AUTHENTICATION_SESSION_ERROR;
468 if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
469 session_result = E_AUTHENTICATION_SESSION_SUCCESS;
473 g_warn_if_fail (auth_result == E_SOURCE_AUTHENTICATION_REJECTED);
475 /* The stored password is bad so delete it from the keyring.
476 * Failure here does not affect the outcome of this operation,
477 * but leave a breadcrumb as evidence that something went wrong. */
479 e_authentication_session_delete_password_sync (
480 session, cancellable, &local_error);
482 if (local_error != NULL) {
483 g_warning ("%s: %s", G_STRFUNC, local_error->message);
484 g_clear_error (&local_error);
487 /* This will return NULL if the authenticating data source
488 * has not yet been submitted to the D-Bus registry service. */
489 source = e_source_registry_server_ref_source (server, source_uid);
490 if (source != NULL) {
492 e_server_side_source_get_allow_auth_prompt (
493 E_SERVER_SIDE_SOURCE (source));
494 g_object_unref (source);
496 allow_auth_prompt = TRUE;
499 /* Check if we're allowed to interrupt the user for a password.
500 * If not, we have no choice but to dismiss the authentication
502 if (!allow_auth_prompt) {
503 session_result = E_AUTHENTICATION_SESSION_DISMISSED;
507 /* Configure a system prompt. */
509 prompt = gcr_system_prompt_open (
510 SYSTEM_PROMPT_TIMEOUT, cancellable, error);
512 if (prompt == NULL) {
513 session_result = E_AUTHENTICATION_SESSION_ERROR;
517 g_object_bind_property (
518 session, "prompt-title",
520 G_BINDING_SYNC_CREATE);
522 g_object_bind_property (
523 session, "prompt-message",
525 G_BINDING_SYNC_CREATE);
527 g_object_bind_property (
528 session, "prompt-description",
529 prompt, "description",
530 G_BINDING_SYNC_CREATE);
532 label = _("Add this password to your keyring");
533 gcr_prompt_set_choice_label (prompt, label);
534 gcr_prompt_set_choice_chosen (prompt, TRUE);
538 /* Prompt the user for a password. */
540 prompt_password = gcr_prompt_password (
541 prompt, cancellable, &local_error);
543 if (local_error != NULL) {
544 session_result = E_AUTHENTICATION_SESSION_ERROR;
545 g_propagate_error (error, local_error);
550 /* No password and no error indicates a dismissal. */
551 if (prompt_password == NULL) {
552 session_result = E_AUTHENTICATION_SESSION_DISMISSED;
556 /* Attempt authentication with the provided password. */
558 password_string = g_string_new (prompt_password);
560 auth_result = e_source_authenticator_try_password_sync (
561 authenticator, password_string, cancellable, error);
563 g_string_free (password_string, TRUE);
564 password_string = NULL;
566 if (auth_result == E_SOURCE_AUTHENTICATION_ERROR) {
567 session_result = E_AUTHENTICATION_SESSION_ERROR;
571 if (auth_result == E_SOURCE_AUTHENTICATION_ACCEPTED) {
572 gboolean permanently;
573 gchar *password_copy;
575 permanently = gcr_prompt_get_choice_chosen (prompt);
576 session_result = E_AUTHENTICATION_SESSION_SUCCESS;
578 /* Close our prompt before storing the password in
579 * the keyring. If the keyring is locked, it will
580 * need to prompt the user for a keyring password,
581 * but it can't do that if our password prompt is
582 * still open since both prompts are system-modal.
583 * Not sure what would happen next; probably the
584 * store operation would either fail or deadlock. */
586 /* XXX Not sure if it's safe to use the prompt's
587 * password string after closing the prompt,
588 * so make a copy here just to be safe. */
589 password_copy = gcr_secure_memory_strdup (prompt_password);
591 /* Failure here does not affect the outcome of this
592 * operation, but leave a breadcrumb as evidence that
593 * something went wrong. */
595 gcr_system_prompt_close (
596 GCR_SYSTEM_PROMPT (prompt),
597 cancellable, &local_error);
599 if (local_error != NULL) {
600 g_warning ("%s: %s", G_STRFUNC, local_error->message);
601 g_clear_error (&local_error);
604 g_object_unref (prompt);
606 e_authentication_session_store_password_sync (
607 session, password_copy, permanently,
608 cancellable, &local_error);
610 if (local_error != NULL) {
611 g_warning ("%s: %s", G_STRFUNC, local_error->message);
612 g_clear_error (&local_error);
615 gcr_secure_memory_strfree (password_copy);
620 g_warn_if_fail (auth_result == E_SOURCE_AUTHENTICATION_REJECTED);
622 gcr_prompt_set_warning (prompt, _("Password was incorrect"));
628 /* Failure here does not affect the outcome of this operation,
629 * but leave a breadcrumb as evidence that something went wrong. */
631 gcr_system_prompt_close (
632 GCR_SYSTEM_PROMPT (prompt),
633 cancellable, &local_error);
635 if (local_error != NULL) {
636 g_warning ("%s: %s", G_STRFUNC, local_error->message);
637 g_clear_error (&local_error);
640 g_object_unref (prompt);
644 switch (session_result) {
645 case E_AUTHENTICATION_SESSION_ERROR:
646 if (error != NULL && *error != NULL)
647 authentication_session_msg (
648 session, "Complete (ERROR - %s)",
651 authentication_session_msg (
652 session, "Complete (ERROR)");
654 case E_AUTHENTICATION_SESSION_SUCCESS:
655 authentication_session_msg (
656 session, "Complete (SUCCESS)");
658 case E_AUTHENTICATION_SESSION_DISMISSED:
659 authentication_session_msg (
660 session, "Complete (DISMISSED)");
663 g_warn_if_reached ();
666 return session_result;
670 authentication_session_execute (EAuthenticationSession *session,
672 GCancellable *cancellable,
673 GAsyncReadyCallback callback,
676 GSimpleAsyncResult *simple;
677 AsyncContext *async_context;
679 g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
681 async_context = g_slice_new0 (AsyncContext);
683 simple = g_simple_async_result_new (
684 G_OBJECT (session), callback, user_data,
685 e_authentication_session_execute);
687 g_simple_async_result_set_check_cancellable (simple, cancellable);
689 g_simple_async_result_set_op_res_gpointer (
690 simple, async_context, (GDestroyNotify) async_context_free);
692 g_simple_async_result_run_in_thread (
693 simple, authentication_session_execute_thread,
694 io_priority, cancellable);
696 g_object_unref (simple);
699 static EAuthenticationSessionResult
700 authentication_session_execute_finish (EAuthenticationSession *session,
701 GAsyncResult *result,
704 GSimpleAsyncResult *simple;
705 AsyncContext *async_context;
707 g_return_val_if_fail (
708 g_simple_async_result_is_valid (
709 result, G_OBJECT (session),
710 e_authentication_session_execute),
711 E_AUTHENTICATION_SESSION_DISMISSED);
713 simple = G_SIMPLE_ASYNC_RESULT (result);
714 async_context = g_simple_async_result_get_op_res_gpointer (simple);
716 if (g_simple_async_result_propagate_error (simple, error))
717 return E_AUTHENTICATION_SESSION_ERROR;
719 return async_context->auth_result;
723 e_authentication_session_class_init (EAuthenticationSessionClass *class)
725 GObjectClass *object_class;
727 g_type_class_add_private (
728 class, sizeof (EAuthenticationSessionPrivate));
730 object_class = G_OBJECT_CLASS (class);
731 object_class->set_property = authentication_session_set_property;
732 object_class->get_property = authentication_session_get_property;
733 object_class->dispose = authentication_session_dispose;
734 object_class->finalize = authentication_session_finalize;
735 object_class->constructed = authentication_session_constructed;
737 class->execute_sync = authentication_session_execute_sync;
738 class->execute = authentication_session_execute;
739 class->execute_finish = authentication_session_execute_finish;
741 g_object_class_install_property (
744 g_param_spec_object (
747 "Handles authentication attempts",
748 E_TYPE_SOURCE_AUTHENTICATOR,
750 G_PARAM_CONSTRUCT_ONLY |
751 G_PARAM_STATIC_STRINGS));
753 g_object_class_install_property (
755 PROP_PROMPT_DESCRIPTION,
756 g_param_spec_string (
757 "prompt-description",
758 "Prompt Description",
759 "The detailed description of the prompt",
762 G_PARAM_STATIC_STRINGS));
764 g_object_class_install_property (
767 g_param_spec_string (
770 "The prompt message for the user",
773 G_PARAM_STATIC_STRINGS));
775 g_object_class_install_property (
778 g_param_spec_string (
781 "The title of the prompt",
784 G_PARAM_STATIC_STRINGS));
786 g_object_class_install_property (
789 g_param_spec_object (
792 "The server to which the session belongs",
793 E_TYPE_SOURCE_REGISTRY_SERVER,
795 G_PARAM_CONSTRUCT_ONLY |
796 G_PARAM_STATIC_STRINGS));
798 g_object_class_install_property (
801 g_param_spec_string (
804 "Unique ID of the data source being authenticated",
807 G_PARAM_CONSTRUCT_ONLY |
808 G_PARAM_STATIC_STRINGS));
812 e_authentication_session_init (EAuthenticationSession *session)
814 session->priv = E_AUTHENTICATION_SESSION_GET_PRIVATE (session);
815 g_mutex_init (&session->priv->property_lock);
819 e-authentication-session-error-quark,
820 e_authentication_session_error);
823 * e_authentication_session_new:
824 * @server: an #ESourceRegistryServer
825 * @authenticator: an #ESourceAuthenticator
826 * @source_uid: a data source identifier
828 * Creates a new #EAuthenticationSession instance for @server using
829 * @authenticator to handle authentication attempts.
831 * Note that @source_uid does not necessarily have to be known to the
832 * @server, as in the case when configuring a new data source, but it
833 * still has to be unique.
835 * Returns: a newly-created #EAuthenticationSession
839 EAuthenticationSession *
840 e_authentication_session_new (ESourceRegistryServer *server,
841 ESourceAuthenticator *authenticator,
842 const gchar *source_uid)
844 g_return_val_if_fail (E_IS_SOURCE_REGISTRY_SERVER (server), NULL);
845 g_return_val_if_fail (E_IS_SOURCE_AUTHENTICATOR (authenticator), NULL);
846 g_return_val_if_fail (source_uid != NULL, NULL);
848 return g_object_new (
849 E_TYPE_AUTHENTICATION_SESSION,
851 "authenticator", authenticator,
852 "source-uid", source_uid, NULL);
856 * e_authentication_session_get_server:
857 * @session: an #EAuthenticationSession
859 * Returns the #ESourceRegistryServer to which @session belongs.
861 * Returns: the #ESourceRegistryServer for @session
865 ESourceRegistryServer *
866 e_authentication_session_get_server (EAuthenticationSession *session)
868 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), NULL);
870 return session->priv->server;
874 * e_authentication_session_get_authenticator:
875 * @session: an #EAuthenticationSession
877 * Returns the #ESourceAuthenticator handling authentication attempts for
878 * @session. This is usually an #EAuthenticationMediator but can also be
879 * a custom collection backend derived from #ECollectionBackend.
881 * Returns: the #ESourceAuthenticator for @session
885 ESourceAuthenticator *
886 e_authentication_session_get_authenticator (EAuthenticationSession *session)
888 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), NULL);
890 return session->priv->authenticator;
894 * e_authentication_session_get_source_uid:
895 * @session: an #EAuthenticationSession
897 * Returns the #ESource:uid of the authenticating data source. The data
898 * source may or may not be known to the #EAuthenticationSession:server.
900 * Returns: the UID of the authenticating data source
905 e_authentication_session_get_source_uid (EAuthenticationSession *session)
907 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), NULL);
909 return session->priv->source_uid;
913 * e_authentication_session_get_prompt_title:
914 * @session: an #EAuthenticationSession
916 * Returns the text used for the password prompt title should prompting
917 * be necessary. See #GcrPrompt for more details about password prompts.
919 * Returns: the password prompt title
924 e_authentication_session_get_prompt_title (EAuthenticationSession *session)
926 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), NULL);
928 return session->priv->prompt_title;
932 * e_authentication_session_dup_prompt_title:
933 * @session: an #EAuthenticationSession
935 * Thread-safe variation of e_authentication_session_get_prompt_title().
936 * Use this function when accessing @session from multiple threads.
938 * The returned string should be freed with g_free() when no longer needed.
940 * Returns: a newly-allocated copy of #EAuthenticationSession:prompt-title
945 e_authentication_session_dup_prompt_title (EAuthenticationSession *session)
947 const gchar *protected;
950 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), NULL);
952 g_mutex_lock (&session->priv->property_lock);
954 protected = e_authentication_session_get_prompt_title (session);
955 duplicate = g_strdup (protected);
957 g_mutex_unlock (&session->priv->property_lock);
963 * e_authentication_session_set_prompt_title:
964 * @session: an #EAuthenticationSession
965 * @prompt_title: the password prompt title, or %NULL
967 * Sets the text used for the password prompt title should prompting be
968 * necessary. See #GcrPrompt for more details about password prompts.
973 e_authentication_session_set_prompt_title (EAuthenticationSession *session,
974 const gchar *prompt_title)
976 g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
978 g_mutex_lock (&session->priv->property_lock);
980 if (g_strcmp0 (session->priv->prompt_title, prompt_title) == 0) {
981 g_mutex_unlock (&session->priv->property_lock);
985 g_free (session->priv->prompt_title);
986 session->priv->prompt_title = g_strdup (prompt_title);
988 g_mutex_unlock (&session->priv->property_lock);
990 g_object_notify (G_OBJECT (session), "prompt-title");
994 * e_authentication_session_get_prompt_message:
995 * @session: an #EAuthenticationSession
997 * Returns the text used for the password prompt message should prompting
998 * be necessary. See #GcrPrompt for more details about password prompts.
1000 * Returns: the password prompt message
1005 e_authentication_session_get_prompt_message (EAuthenticationSession *session)
1007 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), NULL);
1009 return session->priv->prompt_message;
1013 * e_authentication_session_dup_prompt_message:
1014 * @session: an #EAuthenticationSession
1016 * Thread-safe variation of e_authentication_session_get_prompt_message().
1017 * Use this function when accessing @session from multiple threads.
1019 * The returned string should be freed with g_free() when no longer needed.
1021 * Returns: a newly-allocated copy of #EAuthenticationSession:prompt-message
1026 e_authentication_session_dup_prompt_message (EAuthenticationSession *session)
1028 const gchar *protected;
1031 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), NULL);
1033 g_mutex_lock (&session->priv->property_lock);
1035 protected = e_authentication_session_get_prompt_message (session);
1036 duplicate = g_strdup (protected);
1038 g_mutex_unlock (&session->priv->property_lock);
1044 * e_authentication_session_set_prompt_message:
1045 * @session: an #EAuthenticationSession
1046 * @prompt_message: the password prompt message, or %NULL
1048 * Sets the text used for the password prompt message should prompting be
1049 * necessary. See #GcrPrompt for more details about password prompts.
1054 e_authentication_session_set_prompt_message (EAuthenticationSession *session,
1055 const gchar *prompt_message)
1057 g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
1059 g_mutex_lock (&session->priv->property_lock);
1061 if (g_strcmp0 (session->priv->prompt_message, prompt_message) == 0) {
1062 g_mutex_unlock (&session->priv->property_lock);
1066 g_free (session->priv->prompt_message);
1067 session->priv->prompt_message = g_strdup (prompt_message);
1069 g_mutex_unlock (&session->priv->property_lock);
1071 g_object_notify (G_OBJECT (session), "prompt-message");
1075 * e_authentication_session_get_prompt_description:
1076 * @session: an #EAuthenticationSession
1078 * Returns the text used for the password prompt description should prompting
1079 * be necessary. See #GcrPrompt for more details about password prompts.
1081 * Returns: the password prompt description
1086 e_authentication_session_get_prompt_description (EAuthenticationSession *session)
1088 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), NULL);
1090 return session->priv->prompt_description;
1094 * e_authentication_session_dup_prompt_description:
1095 * @session: an #EAuthenticationSession
1097 * Thread-safe variation of e_authentication_session_get_prompt_description().
1098 * Use this function when accessing @session from multiple threads.
1100 * The returned string should be freed with g_free() when no longer needed.
1102 * Returns: a newly-allocated copy of
1103 * #EAuthenticationSession:prompt-description
1108 e_authentication_session_dup_prompt_description (EAuthenticationSession *session)
1110 const gchar *protected;
1113 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), NULL);
1115 g_mutex_lock (&session->priv->property_lock);
1117 protected = e_authentication_session_get_prompt_description (session);
1118 duplicate = g_strdup (protected);
1120 g_mutex_unlock (&session->priv->property_lock);
1126 * e_authentication_session_set_prompt_description:
1127 * @session: an #EAuthenticationSession
1128 * @prompt_description: the password prompt description
1130 * Sets the text used for the password prompt description should prompting
1131 * be necessary. See #GcrPrompt for more details about password prompts.
1136 e_authentication_session_set_prompt_description (EAuthenticationSession *session,
1137 const gchar *prompt_description)
1139 g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
1141 g_mutex_lock (&session->priv->property_lock);
1143 if (g_strcmp0 (session->priv->prompt_description, prompt_description) == 0) {
1144 g_mutex_unlock (&session->priv->property_lock);
1148 g_free (session->priv->prompt_description);
1149 session->priv->prompt_description = g_strdup (prompt_description);
1151 g_mutex_unlock (&session->priv->property_lock);
1153 g_object_notify (G_OBJECT (session), "prompt-description");
1157 * e_authentication_session_execute_sync:
1158 * @session: an #EAuthenticationSession
1159 * @cancellable: optional #GCancellable object, or %NULL
1160 * @error: return location for a #GError, or %NULL
1162 * Executes an authentication session.
1164 * First the secret service is queried for a stored password. If found,
1165 * an authentication attempt is made without disturbing the user. If no
1166 * stored password is found, or if the stored password is rejected, the
1167 * user is shown a system-modal dialog requesting a password. Further
1168 * authentication attempts are repeated with user-provided passwords
1169 * until authentication is verified or the user dismisses the prompt.
1170 * The returned #EAuthenticationSessionResult indicates the outcome.
1172 * If an error occurs while interacting with the secret service, or while
1173 * prompting the user for a password, or while attempting authentication,
1174 * the function sets @error and returns #E_AUTHENTICATION_SESSION_ERROR.
1176 * Returns: the result of the authentication session
1180 EAuthenticationSessionResult
1181 e_authentication_session_execute_sync (EAuthenticationSession *session,
1182 GCancellable *cancellable,
1185 EAuthenticationSessionClass *class;
1187 g_return_val_if_fail (
1188 E_IS_AUTHENTICATION_SESSION (session),
1189 E_AUTHENTICATION_SESSION_DISMISSED);
1191 class = E_AUTHENTICATION_SESSION_GET_CLASS (session);
1192 g_return_val_if_fail (
1193 class->execute_sync != NULL,
1194 E_AUTHENTICATION_SESSION_DISMISSED);
1196 return class->execute_sync (session, cancellable, error);
1200 * e_authentication_session_execute:
1201 * @session: an #EAuthenticationSession
1202 * @io_priority: the I/O priority of the request
1203 * @cancellable: optional #GCancellable object, or %NULL
1204 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1205 * @user_data: data to pass to the callback function
1207 * See e_authentication_session_execute_sync() for details.
1209 * When the operation is finished, @callback will be called. You can then
1210 * call e_authentication_session_execute_finish() to get the result of the
1216 e_authentication_session_execute (EAuthenticationSession *session,
1218 GCancellable *cancellable,
1219 GAsyncReadyCallback callback,
1222 EAuthenticationSessionClass *class;
1224 g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
1226 class = E_AUTHENTICATION_SESSION_GET_CLASS (session);
1227 g_return_if_fail (class->execute != NULL);
1229 return class->execute (
1230 session, io_priority, cancellable, callback, user_data);
1234 * e_authentication_session_execute_finish:
1235 * @session: an #EAuthenticationSession
1236 * @result: a #GAsyncResult
1237 * @error: return location for a #GError, or %NULL
1239 * Finishes the operation started with e_authentication_session_execute().
1241 * If an error occurs while interacting with the secret service, or while
1242 * prompting the user for a password, or while attempting authentication,
1243 * the function sets @error and returns #E_AUTHENTICATION_SESSION_ERROR.
1245 * Returns: the result of the authentication session
1249 EAuthenticationSessionResult
1250 e_authentication_session_execute_finish (EAuthenticationSession *session,
1251 GAsyncResult *result,
1254 EAuthenticationSessionClass *class;
1256 g_return_val_if_fail (
1257 E_IS_AUTHENTICATION_SESSION (session),
1258 E_AUTHENTICATION_SESSION_DISMISSED);
1259 g_return_val_if_fail (
1260 G_IS_ASYNC_RESULT (result),
1261 E_AUTHENTICATION_SESSION_DISMISSED);
1263 class = E_AUTHENTICATION_SESSION_GET_CLASS (session);
1264 g_return_val_if_fail (
1265 class->execute_finish != NULL,
1266 E_AUTHENTICATION_SESSION_DISMISSED);
1268 return class->execute_finish (session, result, error);
1271 /* Helper for e_authentication_session_store_password() */
1273 authentication_session_store_password_thread (GSimpleAsyncResult *simple,
1275 GCancellable *cancellable)
1277 AsyncContext *async_context;
1278 GError *error = NULL;
1280 async_context = g_simple_async_result_get_op_res_gpointer (simple);
1282 e_authentication_session_store_password_sync (
1283 E_AUTHENTICATION_SESSION (object),
1284 async_context->password,
1285 async_context->permanently,
1286 cancellable, &error);
1289 g_simple_async_result_take_error (simple, error);
1293 * e_authentication_session_store_password_sync:
1294 * @session: an #EAuthenticationSession
1295 * @password: the password to store
1296 * @permanently: store permanently or just for the session
1297 * @cancellable: optional #GCancellable object, or %NULL
1298 * @error: return location for a #GError, or %NULL
1300 * Store a password for the data source that @session is representing.
1301 * If @permanently is %TRUE, the password is stored in the default keyring.
1302 * Otherwise the password is stored in the memory-only session keyring. If
1303 * an error occurs, the function sets @error and returns %FALSE.
1305 * Returns: %TRUE on success, %FALSE on error
1310 e_authentication_session_store_password_sync (EAuthenticationSession *session,
1311 const gchar *password,
1312 gboolean permanently,
1313 GCancellable *cancellable,
1317 const gchar *collection;
1319 gchar *display_name;
1321 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), FALSE);
1322 g_return_val_if_fail (password != NULL, FALSE);
1325 collection = SECRET_COLLECTION_DEFAULT;
1327 collection = SECRET_COLLECTION_SESSION;
1329 uid = e_authentication_session_get_source_uid (session);
1330 display_name = g_strdup_printf (KEYRING_ITEM_DISPLAY_FORMAT, uid);
1332 result = secret_password_store_sync (
1333 &schema, collection, display_name,
1334 password, cancellable, error,
1335 KEYRING_ITEM_ATTRIBUTE_NAME, uid,
1338 g_free (display_name);
1344 * e_authentication_session_store_password:
1345 * @session: an #EAuthenticationSession
1346 * @password: the password to store
1347 * @permanently: store permanently or just for the session
1348 * @io_priority: the I/O priority of the request
1349 * @cancellable: optional #GCancellable object, or %NULL
1350 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1351 * @user_data: data to pass to the callback function
1353 * Asynchronously stores a password for the data source that @session
1354 * is representing. If @permanently is %TRUE, the password is stored in the
1355 * default keyring. Otherwise the password is stored in the memory-only
1358 * When the operation is finished, @callback will be called. You can then
1359 * call e_authentication_session_store_password_finish() to get the result
1365 e_authentication_session_store_password (EAuthenticationSession *session,
1366 const gchar *password,
1367 gboolean permanently,
1369 GCancellable *cancellable,
1370 GAsyncReadyCallback callback,
1373 GSimpleAsyncResult *simple;
1374 AsyncContext *async_context;
1376 g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
1377 g_return_if_fail (password != NULL);
1379 async_context = g_slice_new0 (AsyncContext);
1380 async_context->password = g_strdup (password);
1381 async_context->permanently = permanently;
1383 simple = g_simple_async_result_new (
1384 G_OBJECT (session), callback, user_data,
1385 e_authentication_session_store_password);
1387 g_simple_async_result_set_check_cancellable (simple, cancellable);
1389 g_simple_async_result_set_op_res_gpointer (
1390 simple, async_context, (GDestroyNotify) async_context_free);
1392 g_simple_async_result_run_in_thread (
1393 simple, authentication_session_store_password_thread,
1394 io_priority, cancellable);
1396 g_object_unref (simple);
1400 * e_authentication_session_store_password_finish:
1401 * @session: an #EAuthenticationSession
1402 * @result: a #GAsyncResult
1403 * @error: return location for a #GError, or %NULL
1405 * Finished the operation started with
1406 * e_authentication_session_store_password().
1408 * Returns: %TRUE on success, %FALSE on error
1413 e_authentication_session_store_password_finish (EAuthenticationSession *session,
1414 GAsyncResult *result,
1417 GSimpleAsyncResult *simple;
1419 g_return_val_if_fail (
1420 g_simple_async_result_is_valid (
1421 result, G_OBJECT (session),
1422 e_authentication_session_store_password), FALSE);
1424 simple = G_SIMPLE_ASYNC_RESULT (result);
1426 /* Assume success unless a GError is set. */
1427 return !g_simple_async_result_propagate_error (simple, error);
1430 /* Helper for e_authentication_session_store_password() */
1432 authentication_session_lookup_password_thread (GSimpleAsyncResult *simple,
1434 GCancellable *cancellable)
1436 AsyncContext *async_context;
1437 GError *error = NULL;
1439 async_context = g_simple_async_result_get_op_res_gpointer (simple);
1441 e_authentication_session_lookup_password_sync (
1442 E_AUTHENTICATION_SESSION (object), cancellable,
1443 &async_context->password, &error);
1446 g_simple_async_result_take_error (simple, error);
1450 * e_authentication_session_lookup_password_sync:
1451 * @session: an #EAuthenticationSession
1452 * @cancellable: optional #GCancellable object, or %NULL
1453 * @password: return location for the password, or %NULL
1454 * @error: return location for a #GError, or %NULL
1456 * Looks up a password for the data source that @session is
1457 * representing. Both the default and session keyrings are queried.
1459 * Note the boolean return value indicates whether the lookup operation
1460 * itself completed successfully, not whether a password was found. If
1461 * no password was found, the function will set @password to %NULL but
1462 * still return %TRUE. If an error occurs, the function sets @error
1463 * and returns %FALSE.
1465 * Returns: %TRUE on success, %FALSE on error
1470 e_authentication_session_lookup_password_sync (EAuthenticationSession *session,
1471 GCancellable *cancellable,
1477 gboolean success = TRUE;
1478 GError *local_error = NULL;
1480 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), FALSE);
1482 uid = e_authentication_session_get_source_uid (session);
1484 temp = secret_password_lookup_sync (
1485 &schema, cancellable, &local_error,
1486 KEYRING_ITEM_ATTRIBUTE_NAME, uid, NULL);
1488 if (local_error != NULL) {
1489 g_warn_if_fail (temp == NULL);
1490 g_propagate_error (error, local_error);
1492 } else if (password != NULL) {
1493 *password = temp; /* takes ownership */
1495 secret_password_free (temp);
1502 * e_authentication_session_lookup_password:
1503 * @session: an #EAuthenticationSession
1504 * @io_priority: the I/O priority of the request
1505 * @cancellable: optional #GCancellable object, or %NULL
1506 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1507 * @user_data: data to pass to the callback function
1509 * Asynchronously looks up a password for the data source that @session
1510 * is representing. Both the default and session keyrings are queried.
1512 * When the operation is finished, @callback will be called. You can then
1513 * call e_authentication_session_lookup_password_finish() to get the
1514 * result of the operation.
1519 e_authentication_session_lookup_password (EAuthenticationSession *session,
1521 GCancellable *cancellable,
1522 GAsyncReadyCallback callback,
1525 GSimpleAsyncResult *simple;
1526 AsyncContext *async_context;
1528 g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
1530 async_context = g_slice_new0 (AsyncContext);
1532 simple = g_simple_async_result_new (
1533 G_OBJECT (session), callback, user_data,
1534 e_authentication_session_lookup_password);
1536 g_simple_async_result_set_check_cancellable (simple, cancellable);
1538 g_simple_async_result_set_op_res_gpointer (
1539 simple, async_context, (GDestroyNotify) async_context_free);
1541 g_simple_async_result_run_in_thread (
1542 simple, authentication_session_lookup_password_thread,
1543 io_priority, cancellable);
1545 g_object_unref (simple);
1549 * e_authentication_session_lookup_password_finish:
1550 * @session: an #EAuthenticationSession
1551 * @result: a #GAsyncResult
1552 * @password: return location for the password, or %NULL
1553 * @error: return location for a #GError, or %NULL
1555 * Finishes the operation started with
1556 * e_authentication_session_lookup_password().
1558 * Note the boolean return value indicates whether the lookup operation
1559 * itself completed successfully, not whether a password was found. If
1560 * no password was found, the function will set @password to %NULL but
1561 * still return %TRUE. If an error occurs, the function sets @error
1562 * and returns %FALSE.
1564 * Returns: %TRUE on success, %FALSE on error
1569 e_authentication_session_lookup_password_finish (EAuthenticationSession *session,
1570 GAsyncResult *result,
1574 GSimpleAsyncResult *simple;
1575 AsyncContext *async_context;
1577 g_return_val_if_fail (
1578 g_simple_async_result_is_valid (
1579 result, G_OBJECT (session),
1580 e_authentication_session_lookup_password), FALSE);
1582 simple = G_SIMPLE_ASYNC_RESULT (result);
1583 async_context = g_simple_async_result_get_op_res_gpointer (simple);
1585 if (g_simple_async_result_propagate_error (simple, error))
1588 if (password != NULL) {
1589 *password = async_context->password;
1590 async_context->password = NULL;
1596 /* Helper for e_authentication_session_delete_password() */
1598 authentication_session_delete_password_thread (GSimpleAsyncResult *simple,
1600 GCancellable *cancellable)
1602 GError *error = NULL;
1604 e_authentication_session_delete_password_sync (
1605 E_AUTHENTICATION_SESSION (object), cancellable, &error);
1608 g_simple_async_result_take_error (simple, error);
1612 * e_authentication_session_delete_password_sync:
1613 * @session: an #EAuthenticationSession
1614 * @cancellable: optional #GCancellable object, or %NULL
1615 * @error: return location for a #GError, or %NULL
1617 * Deletes the password for the data source that @session is
1618 * representing from either the default keyring or session keyring.
1620 * Note the boolean return value indicates whether the delete operation
1621 * itself completed successfully, not whether a password was found and
1622 * deleted. If no password was found, the function will still return
1623 * %TRUE. If an error occurs, the function sets @error and returns %FALSE.
1625 * Returns: %TRUE on success, %FALSE on error
1630 e_authentication_session_delete_password_sync (EAuthenticationSession *session,
1631 GCancellable *cancellable,
1635 gboolean success = TRUE;
1636 GError *local_error = NULL;
1638 g_return_val_if_fail (E_IS_AUTHENTICATION_SESSION (session), FALSE);
1640 uid = e_authentication_session_get_source_uid (session);
1642 /* The return value indicates whether any passwords were removed,
1643 * not whether the operation completed successfully. So we have
1644 * check the GError directly. */
1645 secret_password_clear_sync (
1646 &schema, cancellable, &local_error,
1647 KEYRING_ITEM_ATTRIBUTE_NAME, uid, NULL);
1649 if (local_error != NULL) {
1650 g_propagate_error (error, local_error);
1658 * e_authentication_session_delete_password:
1659 * @session: an #EAuthenticationSession
1660 * @io_priority: the I/O priority of the request
1661 * @cancellable: optional #GCancellable object, or %NULL
1662 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1663 * @user_data: data to pass to the callback function
1665 * Asyncronously deletes the password for the data source that @session
1666 * is representing from either the default keyring or session keyring.
1668 * When the operation is finished, @callback will be called. You can then
1669 * call e_authentication_session_delete_password_finish() to get the result
1675 e_authentication_session_delete_password (EAuthenticationSession *session,
1677 GCancellable *cancellable,
1678 GAsyncReadyCallback callback,
1681 GSimpleAsyncResult *simple;
1683 g_return_if_fail (E_IS_AUTHENTICATION_SESSION (session));
1685 simple = g_simple_async_result_new (
1686 G_OBJECT (session), callback, user_data,
1687 e_authentication_session_delete_password);
1689 g_simple_async_result_set_check_cancellable (simple, cancellable);
1691 g_simple_async_result_run_in_thread (
1692 simple, authentication_session_delete_password_thread,
1693 io_priority, cancellable);
1695 g_object_unref (simple);
1699 * e_authentication_session_delete_password_finish:
1700 * @session: an #EAuthenticationSession
1701 * @result: a #GAsyncResult
1702 * @error: return location for a #GError, or %NULL
1704 * Finishes the operation started with
1705 * e_authentication_session_delete_password().
1707 * Note the boolean return value indicates whether the delete operation
1708 * itself completed successfully, not whether a password was found and
1709 * deleted. If no password was found, the function will still return
1710 * %TRUE. If an error occurs, the function sets @error and returns %FALSE.
1712 * Returns: %TRUE on success, %FALSE on error
1717 e_authentication_session_delete_password_finish (EAuthenticationSession *session,
1718 GAsyncResult *result,
1721 GSimpleAsyncResult *simple;
1723 g_return_val_if_fail (
1724 g_simple_async_result_is_valid (
1725 result, G_OBJECT (session),
1726 e_authentication_session_delete_password), FALSE);
1728 simple = G_SIMPLE_ASYNC_RESULT (result);
1730 /* Assume success unless a GError is set. */
1731 return !g_simple_async_result_propagate_error (simple, error);