Commit 4367113c authored by Debarshi Ray's avatar Debarshi Ray
Browse files
parent c6c19446
......@@ -167,6 +167,43 @@ if test "$enable_exchange" != "no"; then
AC_DEFINE(GOA_EXCHANGE_ENABLED, 1, [Enable Microsoft Exchange data provider])
fi
# Fedora
AC_DEFINE(GOA_FEDORA_NAME, ["fedora"], [ProviderType and extension point name])
AC_ARG_ENABLE([fedora],
[AS_HELP_STRING([--enable-fedora], [Enable Fedora Account System support])],
[enable_fedora=$enableval],
[enable_fedora=auto])
AC_PATH_PROG([KRB5_CONFIG], krb5-config, none, $PATH:/usr/kerberos/bin)
if test "x$KRB5_CONFIG" != "xnone"; then
KRB5_LIBS="`${KRB5_CONFIG} --libs krb5`"
KRB5_CFLAGS="`${KRB5_CONFIG} --cflags krb5`"
PKG_CHECK_MODULES(GCR, gcr-3, [have_fedora=yes], [have_fedora=no])
else
KRB5_LIBS=""
KRB5_CFLAGS=""
have_fedora=no
fi
AC_SUBST(KRB5_CFLAGS)
AC_SUBST(KRB5_LIBS)
if test "$enable_fedora" != "no"; then
if test "$enable_fedora" == "yes" &&
test "$have_fedora" == "no" ; then
AC_MSG_ERROR([Fedora Account System support requested, but not available])
fi
enable_fedora=$have_fedora
if test "$enable_fedora" == "yes"; then
AC_DEFINE(GCR_API_SUBJECT_TO_CHANGE, 1, [Define to use the GCR API])
AC_DEFINE(GOA_FEDORA_ENABLED, 1, [Enable Fedora Account System provider])
fi
else
enable_fedora=no
fi
AM_CONDITIONAL(BUILD_FEDORA, [test x$enable_fedora != xno])
# Flickr
AC_DEFINE(GOA_FLICKR_NAME, ["flickr"], [ProviderType and extension point name])
AC_ARG_ENABLE([flickr],
......@@ -538,6 +575,7 @@ echo "
introspection: ${found_introspection}
template file: ${with_template_file}
Fedora Account System provider: ${enable_fedora}
Flickr provider: ${enable_flickr} (OAuth 1.0, key:${with_flickr_consumer_key} secret:${with_flickr_consumer_secret})
Foursquare provider: ${enable_foursquare} (id:${with_foursquare_client_id})
Google provider: ${enable_google} (OAuth 2.0, id:${with_google_client_id} secret:${with_google_client_secret})
......
......@@ -133,6 +133,18 @@ config_h.set_quoted('GOA_FACEBOOK_CLIENT_ID', facebook_client_id)
enable_facebook = get_option('facebook')
config_h.set('GOA_FACEBOOK_ENABLED', enable_facebook)
# Fedora
config_h.set_quoted('GOA_FEDORA_NAME', 'fedora')
enable_fedora = get_option('fedora')
if enable_fedora
gcr_dep = dependency('gcr-3')
krb5_dep = dependency('krb5')
config_h.set('GCR_API_SUBJECT_TO_CHANGE', true)
endif
config_h.set('GOA_FEDORA_ENABLED', enable_fedora)
# Flickr
config_h.set_quoted('GOA_FLICKR_NAME', 'flickr')
......@@ -313,6 +325,7 @@ if enable_facebook
output += ' (OAuth 2.0, id:@0@)'.format(facebook_client_id)
endif
output += '\n'
output += ' Fedora Account System provider: ' + enable_fedora.to_string() + '\n'
output += ' Flickr provider: ' + enable_flickr.to_string()
if enable_flickr
output += ' (OAuth 1.0, key:@0@)'.format(flickr_consumer_key)
......
......@@ -103,6 +103,11 @@ libgoa_backend_1_0_la_SOURCES = \
$(NULL)
if BUILD_KERBEROS
if BUILD_FEDORA
libgoa_backend_1_0_la_SOURCES += \
goafedoraprovider.h goafedoraprovider.c
endif
libgoa_backend_1_0_la_SOURCES += \
goakerberosprovider.h goakerberosprovider.c
endif
......
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* Copyright © 2019 Red Hat, Inc.
*
* 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; either
* version 2 of the License, or (at your option) any later version.
*
* 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/>.
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#include "goaprovider.h"
#include "goaprovider-priv.h"
#include "goafedoraprovider.h"
#include "goautils.h"
#include "goaidentity.h"
#include "goaidentitymanagererror.h"
#include <gcr/gcr.h>
#include "org.gnome.Identity.h"
struct _GoaFedoraProvider
{
GoaProvider parent_instance;
};
static GoaIdentityServiceManager *identity_manager;
static GMutex identity_manager_mutex;
static GCond identity_manager_condition;
static GDBusObjectManager *object_manager;
static GMutex object_manager_mutex;
static GCond object_manager_condition;
static void ensure_identity_manager (void);
static void ensure_object_manager (void);
static char *sign_in_identity_sync (GoaFedoraProvider *self,
const char *identifier,
const char *password,
const char *preauth_source,
GCancellable *cancellable,
GError **error);
static void sign_in_thread (GTask *result,
GoaFedoraProvider *self,
gpointer task_data,
GCancellable *cancellable);
static GoaIdentityServiceIdentity *get_identity_from_object_manager (GoaFedoraProvider *self,
const char *identifier);
static gboolean dbus_proxy_reload_properties_sync (GDBusProxy *proxy,
GCancellable *cancellable);
static void goa_fedora_provider_module_init (void);
static void create_object_manager (void);
static void create_identity_manager (void);
G_DEFINE_TYPE_WITH_CODE (GoaFedoraProvider, goa_fedora_provider, GOA_TYPE_PROVIDER,
goa_fedora_provider_module_init ();
goa_provider_ensure_extension_points_registered ();
g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
g_define_type_id,
GOA_KERBEROS_NAME,
0));
static void
goa_fedora_provider_module_init (void)
{
create_object_manager ();
create_identity_manager ();
g_debug ("activated Fedora provider");
}
static const gchar *
get_provider_type (GoaProvider *provider)
{
return GOA_FEDORA_NAME;
}
static gchar *
get_provider_name (GoaProvider *provider, GoaObject *object)
{
return g_strdup(_("Fedora"));
}
static GoaProviderGroup
get_provider_group (GoaProvider *_provider)
{
return GOA_PROVIDER_GROUP_TICKETING;
}
static GoaProviderFeatures
get_provider_features (GoaProvider *_provider)
{
return GOA_PROVIDER_FEATURE_TICKETING;
}
static GIcon *
get_provider_icon (GoaProvider *provider, GoaObject *object)
{
return g_themed_icon_new_with_default_fallbacks ("dialog-password-symbolic");
}
typedef struct
{
GCancellable *cancellable;
GtkDialog *dialog;
GMainLoop *loop;
GtkWidget *cluebar;
GtkWidget *cluebar_label;
GtkWidget *connect_button;
GtkWidget *progress_grid;
GtkWidget *principal;
gchar *account_object_path;
GError *error;
} SignInRequest;
static void
translate_error (GError **error)
{
if (!g_dbus_error_is_remote_error (*error))
return;
g_dbus_error_strip_remote_error (*error);
}
static void
sign_in_identity (GoaFedoraProvider *self,
const char *identifier,
const char *password,
const char *preauth_source,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *operation_result;
operation_result = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (operation_result, (gpointer) identifier);
g_object_set_data (G_OBJECT (operation_result),
"password",
(gpointer)
password);
g_object_set_data_full (G_OBJECT (operation_result),
"preauthentication-source",
g_strdup (preauth_source),
g_free);
g_task_run_in_thread (operation_result, (GTaskThreadFunc) sign_in_thread);
g_object_unref (operation_result);
}
static gchar *
sign_in_identity_finish (GoaFedoraProvider *self,
GAsyncResult *result,
GError **error)
{
GTask *task;
g_return_val_if_fail (GOA_IS_FEDORA_PROVIDER (self), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
g_return_val_if_fail (g_task_is_valid (result, self), NULL);
task = G_TASK (result);
return g_task_propagate_pointer (task, error);
}
static gboolean
get_ticket_sync (GoaFedoraProvider *self,
GoaObject *object,
gboolean is_interactive,
GCancellable *cancellable,
GError **error)
{
GVariant *credentials = NULL;
GError *lookup_error;
GError *sign_in_error;
GoaAccount *account;
GoaTicketing *ticketing;
GVariant *details;
const char *identifier;
const char *password;
const char *preauth_source;
char *object_path = NULL;
gboolean ret = FALSE;
account = goa_object_get_account (object);
identifier = goa_account_get_identity (account);
ticketing = goa_object_get_ticketing (object);
if (ticketing == NULL)
{
g_set_error (error,
GOA_ERROR,
GOA_ERROR_NOT_SUPPORTED,
_("Ticketing is disabled for account"));
goto out;
}
details = goa_ticketing_get_details (ticketing);
preauth_source = NULL;
g_variant_lookup (details, "preauthentication-source", "&s", &preauth_source);
password = NULL;
lookup_error = NULL;
credentials = goa_utils_lookup_credentials_sync (GOA_PROVIDER (self),
object,
cancellable,
&lookup_error);
if (credentials == NULL && !is_interactive)
{
if (lookup_error != NULL)
g_propagate_error (error, lookup_error);
else
g_set_error (error,
GOA_ERROR,
GOA_ERROR_NOT_AUTHORIZED,
_("Could not find saved credentials for principal “%s” in keyring"), identifier);
goto out;
}
else if (credentials != NULL)
{
gboolean has_password;
has_password = g_variant_lookup (credentials, "password", "&s", &password);
if (!has_password && !is_interactive)
{
g_set_error (error,
GOA_ERROR,
GOA_ERROR_NOT_AUTHORIZED,
_("Did not find password for principal “%s” in credentials"),
identifier);
goto out;
}
}
sign_in_error = NULL;
object_path = sign_in_identity_sync (self,
identifier,
password,
preauth_source,
cancellable,
&sign_in_error);
if (sign_in_error != NULL)
{
g_propagate_error (error, sign_in_error);
goto out;
}
ret = TRUE;
out:
g_clear_object (&account);
g_clear_object (&ticketing);
g_free (object_path);
g_clear_pointer (&credentials, g_variant_unref);
return ret;
}
static void
notify_is_temporary_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
{
GoaAccount *account;
gboolean is_temporary;
account = GOA_ACCOUNT (object);
is_temporary = goa_account_get_is_temporary (account);
/* Toggle IsTemporary */
goa_utils_keyfile_set_boolean (account, "IsTemporary", is_temporary);
/* Set/unset SessionId */
if (is_temporary)
{
GDBusConnection *connection;
const gchar *guid;
connection = G_DBUS_CONNECTION (user_data);
guid = g_dbus_connection_get_guid (connection);
goa_utils_keyfile_set_string (account, "SessionId", guid);
}
else
goa_utils_keyfile_remove_key (account, "SessionId");
}
static gboolean
on_handle_get_ticket (GoaTicketing *interface,
GDBusMethodInvocation *invocation)
{
GoaObject *object;
GoaAccount *account;
GoaProvider *provider;
GError *error;
gboolean got_ticket;
const gchar *id;
const gchar *method_name;
const gchar *provider_type;
object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (interface)));
account = goa_object_peek_account (object);
id = goa_account_get_id (account);
provider_type = goa_account_get_provider_type (account);
method_name = g_dbus_method_invocation_get_method_name (invocation);
g_debug ("Handling %s for account (%s, %s)", method_name, provider_type, id);
provider = goa_provider_get_for_provider_type (provider_type);
error = NULL;
got_ticket = get_ticket_sync (GOA_FEDORA_PROVIDER (provider),
object,
TRUE /* Allow interaction */,
NULL,
&error);
if (!got_ticket)
g_dbus_method_invocation_take_error (invocation, error);
else
goa_ticketing_complete_get_ticket (interface, invocation);
g_object_unref (provider);
return TRUE;
}
static gboolean
build_object (GoaProvider *provider,
GoaObjectSkeleton *object,
GKeyFile *key_file,
const gchar *group,
GDBusConnection *connection,
gboolean just_added,
GError **error)
{
GoaAccount *account;
GoaTicketing *ticketing = NULL;
gboolean ticketing_enabled;
gboolean ret = FALSE;
if (!GOA_PROVIDER_CLASS (goa_fedora_provider_parent_class)->build_object (provider,
object,
key_file,
group,
connection,
just_added,
error))
goto out;
account = goa_object_get_account (GOA_OBJECT (object));
ticketing = goa_object_get_ticketing (GOA_OBJECT (object));
ticketing_enabled = g_key_file_get_boolean (key_file, group, "TicketingEnabled", NULL);
if (ticketing_enabled)
{
if (ticketing == NULL)
{
char *preauthentication_source;
GVariantBuilder details;
ticketing = goa_ticketing_skeleton_new ();
g_signal_connect (ticketing,
"handle-get-ticket",
G_CALLBACK (on_handle_get_ticket),
NULL);
goa_object_skeleton_set_ticketing (object, ticketing);
g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
preauthentication_source = g_key_file_get_string (key_file, group, "PreauthenticationSource", NULL);
if (preauthentication_source)
g_variant_builder_add (&details, "{ss}", "preauthentication-source", preauthentication_source);
g_object_set (G_OBJECT (ticketing), "details", g_variant_builder_end (&details), NULL);
}
}
else if (ticketing != NULL)
{
goa_object_skeleton_set_ticketing (object, NULL);
}
if (just_added)
{
goa_account_set_ticketing_disabled (account, !ticketing_enabled);
g_signal_connect (account,
"notify::is-temporary",
G_CALLBACK (notify_is_temporary_cb),
connection);
g_signal_connect (account,
"notify::ticketing-disabled",
G_CALLBACK (goa_util_account_notify_property_cb),
(gpointer) "TicketingEnabled");
}
ret = TRUE;
out:
g_clear_object (&ticketing);
return ret;
}
static void
add_entry (GtkWidget *grid,
gint row,
const gchar *text,
GtkWidget **out_entry)
{
GtkStyleContext *context;
GtkWidget *label;
GtkWidget *entry;
label = gtk_label_new_with_mnemonic (text);
context = gtk_widget_get_style_context (label);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
gtk_widget_set_halign (label, GTK_ALIGN_END);
gtk_widget_set_hexpand (label, TRUE);
gtk_grid_attach (GTK_GRID (grid), label, 0, row, 1, 1);
entry = gtk_entry_new ();
gtk_widget_set_hexpand (entry, TRUE);
gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
gtk_grid_attach (GTK_GRID (grid), entry, 1, row, 3, 1);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
if (out_entry != NULL)
*out_entry = entry;
}
static gchar *
normalize_principal (const gchar *principal, gchar **out_realm)
{
gchar *domain = NULL;
gchar *realm = NULL;
gchar *ret = NULL;
gchar *username = NULL;
if (!goa_utils_parse_email_address (principal, &username, &domain))
goto out;
realm = g_utf8_strup (domain, -1);
ret = g_strconcat (username, "@", realm, NULL);
if (out_realm != NULL)
{
*out_realm = realm;
realm = NULL;
}
out:
g_free (domain);
g_free (realm);
g_free (username);
return ret;
}
static void
on_principal_changed (GtkEditable *editable, gpointer user_data)
{
SignInRequest *request = user_data;
gboolean can_add;
const gchar *principal;
principal = gtk_entry_get_text (GTK_ENTRY (request->principal));
can_add = goa_utils_parse_email_address (principal, NULL, NULL);
gtk_dialog_set_response_sensitive (request->dialog, GTK_RESPONSE_OK, can_add);
}
static void
show_progress_ui (GtkContainer *container, gboolean progress)
{
GList *children;
GList *l;
children = gtk_container_get_children (container);
for (l = children; l != NULL; l = l->next)
{
GtkWidget *widget = GTK_WIDGET (l->data);
gdouble opacity;
opacity = progress ? 1.0 : 0.0;
gtk_widget_set_opacity (widget, opacity);
}
g_list_free (children);
}
static void
create_account_details_ui (GoaFedoraProvider *self,
GtkDialog *dialog,
GtkWidget *vbox,
gboolean new_account,
SignInRequest *request)
{
GtkWidget *grid0;
GtkWidget *grid1;
GtkWidget *label;
GtkWidget *spinner;
gint row;
gint width;
goa_utils_set_dialog_title (GOA_PROVIDER (self), dialog, new_account);
grid0 = gtk_grid_new ();
gtk_container_set_border_width (GTK_CONTAINER (grid0), 5);
gtk_widget_set_margin_bottom (grid0, 6);
gtk_orientable_set_orientation (GTK_ORIENTABLE (grid0), GTK_ORIENTATION_VERTICAL);
gtk_grid_set_row_spacing (GTK_GRID (grid0), 12);