Blame SOURCES/kerberos-smartcard.patch

1e691d
From 3753904f1de123a724438bf7f0c58aac00ce4ef4 Mon Sep 17 00:00:00 2001
1e691d
From: Ray Strode <rstrode@redhat.com>
1e691d
Date: Tue, 21 Oct 2014 10:38:17 -0400
1e691d
Subject: [PATCH 1/2] ticketing: add new details property
1e691d
1e691d
This commit adds a new "details" variant for attaching metadata
1e691d
about tickets getting requested via the ticketing interface.
1e691d
1e691d
This will give the kerberos account provider a place to tuck away
1e691d
kerberos-specific preauthentication configuration for the tickets
1e691d
associated with smartcard backed kerberos accounts.
1e691d
---
1e691d
 data/dbus-interfaces.xml | 2 ++
1e691d
 1 file changed, 2 insertions(+)
1e691d
1e691d
diff --git a/data/dbus-interfaces.xml b/data/dbus-interfaces.xml
1e691d
index 5bf26e9..fa8b18c 100644
1e691d
--- a/data/dbus-interfaces.xml
1e691d
+++ b/data/dbus-interfaces.xml
1e691d
@@ -726,6 +726,8 @@
1e691d
       ticketing capabilities.
1e691d
   -->
1e691d
   <interface name="org.gnome.OnlineAccounts.Ticketing">
1e691d
+    <property name="details" type="a{ss}" access="read"/>
1e691d
+
1e691d
     
1e691d
       GetTicket:
1e691d
 
1e691d
-- 
1e691d
2.1.0
1e691d
1e691d
1e691d
From 1544883b52453ba8e69e78b5bdacf7a57053326c Mon Sep 17 00:00:00 2001
1e691d
From: Ray Strode <rstrode@redhat.com>
1e691d
Date: Tue, 21 Oct 2014 10:46:50 -0400
1e691d
Subject: [PATCH 2/2] kerberos: Support refreshing smartcard authenticated
1e691d
 kerberos tickets
1e691d
1e691d
Right now gnome-online-accounts doesn't manage smartcard based
1e691d
kerberos credentials very well.  The sign-in button just fails.
1e691d
1e691d
This commit adds support for tickets granted through smartcards.
1e691d
1e691d
Note, at the moment we don't provide a way to add new smartcard based
1e691d
accounts, merely, manage existing ones that are added implicitly by
1e691d
logging in with a smartcard, or by explicit kinit.
1e691d
1e691d
https://bugzilla.gnome.org/show_bug.cgi?id=739594
1e691d
---
1e691d
 src/goabackend/goakerberosprovider.c         | 43 +++++++++++++++++
1e691d
 src/goaidentity/goaidentitymanager.c         |  2 +
1e691d
 src/goaidentity/goaidentitymanager.h         |  2 +
1e691d
 src/goaidentity/goaidentityservice.c         | 19 +++++++-
1e691d
 src/goaidentity/goakerberosidentity.c        | 71 +++++++++++++++++++++++++++-
1e691d
 src/goaidentity/goakerberosidentity.h        |  2 +
1e691d
 src/goaidentity/goakerberosidentitymanager.c | 14 ++++--
1e691d
 7 files changed, 146 insertions(+), 7 deletions(-)
1e691d
1e691d
diff --git a/src/goabackend/goakerberosprovider.c b/src/goabackend/goakerberosprovider.c
1e691d
index b2958b2..f9c54cd 100644
1e691d
--- a/src/goabackend/goakerberosprovider.c
1e691d
+++ b/src/goabackend/goakerberosprovider.c
1e691d
@@ -370,6 +370,7 @@ on_secret_keys_exchanged_for_sign_in (GoaKerberosProvider *self,
1e691d
 {
1e691d
   const char       *identifier;
1e691d
   const char       *password;
1e691d
+  const char       *preauth_source;
1e691d
   GCancellable     *cancellable;
1e691d
   GError           *error;
1e691d
   GVariantBuilder   details;
1e691d
@@ -387,6 +388,7 @@ on_secret_keys_exchanged_for_sign_in (GoaKerberosProvider *self,
1e691d
 
1e691d
   cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
1e691d
   password = g_object_get_data (G_OBJECT (operation_result), "password");
1e691d
+  preauth_source = g_object_get_data (G_OBJECT (operation_result), "preauthentication-source");
1e691d
   identifier = g_simple_async_result_get_source_tag (operation_result);
1e691d
 
1e691d
   g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
1e691d
@@ -403,6 +405,11 @@ on_secret_keys_exchanged_for_sign_in (GoaKerberosProvider *self,
1e691d
       g_free (secret);
1e691d
     }
1e691d
 
1e691d
+  if (preauth_source != NULL)
1e691d
+    {
1e691d
+      g_variant_builder_add (&details, "{ss}", "preauthentication-source", preauth_source);
1e691d
+    }
1e691d
+
1e691d
   goa_identity_service_manager_call_sign_in (self->identity_manager,
1e691d
                                              identifier,
1e691d
                                              g_variant_builder_end (&details),
1e691d
@@ -538,6 +545,7 @@ static void
1e691d
 sign_in_identity (GoaKerberosProvider  *self,
1e691d
                   const char           *identifier,
1e691d
                   const char           *password,
1e691d
+                  const char           *preauth_source,
1e691d
                   GCancellable         *cancellable,
1e691d
                   GAsyncReadyCallback   callback,
1e691d
                   gpointer              user_data)
1e691d
@@ -560,6 +568,11 @@ sign_in_identity (GoaKerberosProvider  *self,
1e691d
                      (gpointer)
1e691d
                      password);
1e691d
 
1e691d
+  g_object_set_data_full (G_OBJECT (operation_result),
1e691d
+                          "preauthentication-source",
1e691d
+                          g_strdup (preauth_source),
1e691d
+                          g_free);
1e691d
+
1e691d
   ensure_identity_manager (self,
1e691d
                            cancellable,
1e691d
                            (GAsyncReadyCallback)
1e691d
@@ -691,8 +704,11 @@ get_ticket_sync (GoaKerberosProvider *self,
1e691d
   GVariant            *credentials;
1e691d
   GError              *lookup_error;
1e691d
   GoaAccount          *account;
1e691d
+  GoaTicketing        *ticketing;
1e691d
+  GVariant            *details;
1e691d
   const char          *identifier;
1e691d
   const char          *password;
1e691d
+  const char          *preauth_source;
1e691d
   SignInRequest        request;
1e691d
   gboolean             ret;
1e691d
 
1e691d
@@ -700,6 +716,13 @@ get_ticket_sync (GoaKerberosProvider *self,
1e691d
 
1e691d
   account = goa_object_peek_account (object);
1e691d
   identifier = goa_account_get_identity (account);
1e691d
+
1e691d
+  ticketing = goa_object_get_ticketing (GOA_OBJECT (object));
1e691d
+  details = goa_ticketing_get_details (ticketing);
1e691d
+
1e691d
+  preauth_source = NULL;
1e691d
+  g_variant_lookup (details, "preauthentication-source", "&s", &preauth_source);
1e691d
+
1e691d
   password = NULL;
1e691d
 
1e691d
   lookup_error = NULL;
1e691d
@@ -742,6 +765,7 @@ get_ticket_sync (GoaKerberosProvider *self,
1e691d
   sign_in_identity (self,
1e691d
                     identifier,
1e691d
                     password,
1e691d
+                    preauth_source,
1e691d
                     cancellable,
1e691d
                     (GAsyncReadyCallback)
1e691d
                     on_account_signed_in,
1e691d
@@ -758,6 +782,8 @@ get_ticket_sync (GoaKerberosProvider *self,
1e691d
 
1e691d
   ret = TRUE;
1e691d
 out:
1e691d
+  g_clear_object (&ticketing);
1e691d
+
1e691d
   if (credentials != NULL)
1e691d
     g_variant_unref (credentials);
1e691d
 
1e691d
@@ -855,6 +881,9 @@ build_object (GoaProvider         *provider,
1e691d
     {
1e691d
       if (ticketing == NULL)
1e691d
         {
1e691d
+          char            *preauthentication_source;
1e691d
+          GVariantBuilder  details;
1e691d
+
1e691d
           ticketing = goa_ticketing_skeleton_new ();
1e691d
 
1e691d
           g_signal_connect (ticketing,
1e691d
@@ -864,6 +893,13 @@ build_object (GoaProvider         *provider,
1e691d
 
1e691d
           goa_object_skeleton_set_ticketing (object, ticketing);
1e691d
 
1e691d
+          g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
1e691d
+
1e691d
+	  preauthentication_source = g_key_file_get_string (key_file, group, "PreauthenticationSource", NULL);
1e691d
+          if (preauthentication_source)
1e691d
+            g_variant_builder_add (&details, "{ss}", "preauthentication-source", preauthentication_source);
1e691d
+
1e691d
+	  g_object_set (G_OBJECT (ticketing), "details", g_variant_builder_end (&details), NULL);
1e691d
         }
1e691d
     }
1e691d
   else if (ticketing != NULL)
1e691d
@@ -1274,12 +1310,18 @@ on_system_prompt_answered_for_initial_sign_in (GcrPrompt          *prompt,
1e691d
   GError              *error;
1e691d
   const char          *principal;
1e691d
   const char          *password;
1e691d
+  const char          *preauth_source;
1e691d
   GcrSecretExchange   *secret_exchange;
1e691d
 
1e691d
   self = GOA_KERBEROS_PROVIDER (g_async_result_get_source_object (G_ASYNC_RESULT (operation_result)));
1e691d
   principal = g_object_get_data (G_OBJECT (operation_result), "principal");
1e691d
   cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
1e691d
 
1e691d
+  /* We currently don't prompt the user to choose a preauthentication source during initial sign in
1e691d
+   * so we assume there's no preauthentication source
1e691d
+   */
1e691d
+  preauth_source = NULL;
1e691d
+
1e691d
   error = NULL;
1e691d
   password = gcr_prompt_password_finish (prompt, result, &error);
1e691d
 
1e691d
@@ -1313,6 +1355,7 @@ on_system_prompt_answered_for_initial_sign_in (GcrPrompt          *prompt,
1e691d
   sign_in_identity (self,
1e691d
                     principal,
1e691d
                     password,
1e691d
+                    preauth_source,
1e691d
                     cancellable,
1e691d
                     (GAsyncReadyCallback)
1e691d
                     on_initial_sign_in_done,
1e691d
diff --git a/src/goaidentity/goaidentitymanager.c b/src/goaidentity/goaidentitymanager.c
1e691d
index 40d2225..22dcd97 100644
1e691d
--- a/src/goaidentity/goaidentitymanager.c
1e691d
+++ b/src/goaidentity/goaidentitymanager.c
1e691d
@@ -202,6 +202,7 @@ void
1e691d
 goa_identity_manager_sign_identity_in (GoaIdentityManager     *self,
1e691d
                                        const char             *identifier,
1e691d
                                        gconstpointer           initial_password,
1e691d
+                                       const char             *preauth_source,
1e691d
                                        GoaIdentitySignInFlags  flags,
1e691d
                                        GoaIdentityInquiryFunc  inquiry_func,
1e691d
                                        gpointer                inquiry_data,
1e691d
@@ -212,6 +213,7 @@ goa_identity_manager_sign_identity_in (GoaIdentityManager     *self,
1e691d
   GOA_IDENTITY_MANAGER_GET_IFACE (self)->sign_identity_in (self,
1e691d
                                                            identifier,
1e691d
                                                            initial_password,
1e691d
+                                                           preauth_source,
1e691d
                                                            flags,
1e691d
                                                            inquiry_func,
1e691d
                                                            inquiry_data,
1e691d
diff --git a/src/goaidentity/goaidentitymanager.h b/src/goaidentity/goaidentitymanager.h
1e691d
index 89e6b6e..755053a 100644
1e691d
--- a/src/goaidentity/goaidentitymanager.h
1e691d
+++ b/src/goaidentity/goaidentitymanager.h
1e691d
@@ -77,6 +77,7 @@ struct _GoaIdentityManagerInterface
1e691d
   void (* sign_identity_in) (GoaIdentityManager     *identity_manager,
1e691d
                              const char             *identifier,
1e691d
                              gconstpointer           initial_password,
1e691d
+                             const char             *preauth_source,
1e691d
                              GoaIdentitySignInFlags  flags,
1e691d
                              GoaIdentityInquiryFunc  inquiry_func,
1e691d
                              gpointer                inquiry_data,
1e691d
@@ -140,6 +141,7 @@ GList *goa_identity_manager_list_identities_finish (GoaIdentityManager  *identit
1e691d
 void goa_identity_manager_sign_identity_in (GoaIdentityManager     *identity_manager,
1e691d
                                             const char             *identifier,
1e691d
                                             gconstpointer           initial_password,
1e691d
+                                            const char             *preauth_source,
1e691d
                                             GoaIdentitySignInFlags  flags,
1e691d
                                             GoaIdentityInquiryFunc  inquiry_func,
1e691d
                                             gpointer                inquiry_data,
1e691d
diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c
1e691d
index 06fb946..38bbde6 100644
1e691d
--- a/src/goaidentity/goaidentityservice.c
1e691d
+++ b/src/goaidentity/goaidentityservice.c
1e691d
@@ -60,6 +60,7 @@ static void
1e691d
 sign_in (GoaIdentityService     *self,
1e691d
          const char             *identifier,
1e691d
          gconstpointer           initial_password,
1e691d
+         const char             *preauth_source,
1e691d
          GoaIdentitySignInFlags  flags,
1e691d
          GCancellable           *cancellable,
1e691d
          GAsyncReadyCallback     callback,
1e691d
@@ -312,7 +313,8 @@ static void
1e691d
 read_sign_in_details (GoaIdentityServiceManager  *manager,
1e691d
                       GVariant                   *details,
1e691d
                       GoaIdentitySignInFlags     *flags,
1e691d
-                      char                      **secret_key)
1e691d
+                      char                      **secret_key,
1e691d
+                      char                      **preauth_source)
1e691d
 {
1e691d
   GVariantIter  iter;
1e691d
   char          *key;
1e691d
@@ -324,6 +326,8 @@ read_sign_in_details (GoaIdentityServiceManager  *manager,
1e691d
     {
1e691d
       if (g_strcmp0 (key, "initial-password") == 0)
1e691d
         *secret_key = g_strdup (value);
1e691d
+      else if (g_strcmp0 (key, "preauthentication-source") == 0)
1e691d
+        *preauth_source = g_strdup (value);
1e691d
       else if (g_strcmp0 (key, "disallow-renewal") == 0
1e691d
                && g_strcmp0 (value, "true") == 0)
1e691d
         *flags |= GOA_IDENTITY_SIGN_IN_FLAGS_DISALLOW_RENEWAL;
1e691d
@@ -346,13 +350,15 @@ goa_identity_service_handle_sign_in (GoaIdentityServiceManager *manager,
1e691d
   GSimpleAsyncResult     *operation_result;
1e691d
   GoaIdentitySignInFlags  flags;
1e691d
   char                   *secret_key;
1e691d
+  char                   *preauth_source;
1e691d
   gconstpointer           initial_password;
1e691d
   GCancellable           *cancellable;
1e691d
 
1e691d
   secret_key = NULL;
1e691d
+  preauth_source = NULL;
1e691d
   initial_password = NULL;
1e691d
 
1e691d
-  read_sign_in_details (manager, details, &flags, &secret_key);
1e691d
+  read_sign_in_details (manager, details, &flags, &secret_key, &preauth_source);
1e691d
 
1e691d
   if (secret_key != NULL)
1e691d
     {
1e691d
@@ -397,12 +403,14 @@ goa_identity_service_handle_sign_in (GoaIdentityServiceManager *manager,
1e691d
   sign_in (self,
1e691d
            identifier,
1e691d
            initial_password,
1e691d
+           preauth_source,
1e691d
            flags,
1e691d
            cancellable,
1e691d
            (GAsyncReadyCallback)
1e691d
            on_sign_in_done,
1e691d
            operation_result);
1e691d
 
1e691d
+  g_free (preauth_source);
1e691d
   g_object_unref (cancellable);
1e691d
 
1e691d
   return TRUE;
1e691d
@@ -868,6 +876,7 @@ add_temporary_account (GoaIdentityService *self,
1e691d
                        GoaIdentity        *identity)
1e691d
 {
1e691d
   char               *realm;
1e691d
+  char               *preauth_source;
1e691d
   const char         *principal;
1e691d
   char               *principal_for_display;
1e691d
   GSimpleAsyncResult *operation_result;
1e691d
@@ -894,12 +903,15 @@ add_temporary_account (GoaIdentityService *self,
1e691d
                                                               identity);
1e691d
 
1e691d
   realm = goa_kerberos_identity_get_realm_name (GOA_KERBEROS_IDENTITY (identity));
1e691d
+  preauth_source = goa_kerberos_identity_get_preauthentication_source (GOA_KERBEROS_IDENTITY (identity));
1e691d
 
1e691d
   g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT);
1e691d
 
1e691d
   g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
1e691d
   g_variant_builder_add (&details, "{ss}", "Realm", realm);
1e691d
   g_variant_builder_add (&details, "{ss}", "IsTemporary", "true");
1e691d
+  if (preauth_source != NULL)
1e691d
+    g_variant_builder_add (&details, "{ss}", "PreauthenticationSource", preauth_source);
1e691d
   g_variant_builder_add (&details, "{ss}", "TicketingEnabled", "true");
1e691d
 
1e691d
 
1e691d
@@ -925,6 +937,7 @@ add_temporary_account (GoaIdentityService *self,
1e691d
                                 on_account_added,
1e691d
                                 operation_result);
1e691d
   g_free (realm);
1e691d
+  g_free (preauth_source);
1e691d
   g_free (principal_for_display);
1e691d
 }
1e691d
 
1e691d
@@ -1261,6 +1274,7 @@ static void
1e691d
 sign_in (GoaIdentityService     *self,
1e691d
          const char             *identifier,
1e691d
          gconstpointer           initial_password,
1e691d
+         const char             *preauth_source,
1e691d
          GoaIdentitySignInFlags  flags,
1e691d
          GCancellable           *cancellable,
1e691d
          GAsyncReadyCallback     callback,
1e691d
@@ -1288,6 +1302,7 @@ sign_in (GoaIdentityService     *self,
1e691d
   goa_identity_manager_sign_identity_in (self->priv->identity_manager,
1e691d
                                          identifier,
1e691d
                                          initial_password,
1e691d
+                                         preauth_source,
1e691d
                                          flags,
1e691d
                                          (GoaIdentityInquiryFunc)
1e691d
                                          on_identity_inquiry,
1e691d
diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c
1e691d
index d501a59..4370a09 100644
1e691d
--- a/src/goaidentity/goakerberosidentity.c
1e691d
+++ b/src/goaidentity/goakerberosidentity.c
1e691d
@@ -47,6 +47,8 @@ struct _GoaKerberosIdentityPrivate
1e691d
   char *identifier;
1e691d
   guint identifier_idle_id;
1e691d
 
1e691d
+  char *preauth_identity_source;
1e691d
+
1e691d
   krb5_timestamp expiration_time;
1e691d
   guint          expiration_time_idle_id;
1e691d
 
1e691d
@@ -106,6 +108,8 @@ goa_kerberos_identity_dispose (GObject *object)
1e691d
 
1e691d
   G_LOCK (identity_lock);
1e691d
   clear_alarms (self);
1e691d
+  g_clear_pointer (&self->priv->preauth_identity_source,
1e691d
+                   g_free);
1e691d
   G_UNLOCK (identity_lock);
1e691d
 
1e691d
   G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->dispose (object);
1e691d
@@ -406,6 +410,12 @@ goa_kerberos_identity_get_realm_name (GoaKerberosIdentity *self)
1e691d
   return realm_name;
1e691d
 }
1e691d
 
1e691d
+char *
1e691d
+goa_kerberos_identity_get_preauthentication_source (GoaKerberosIdentity *self)
1e691d
+{
1e691d
+  return g_strdup (self->priv->preauth_identity_source);
1e691d
+}
1e691d
+
1e691d
 static const char *
1e691d
 goa_kerberos_identity_get_identifier (GoaIdentity *identity)
1e691d
 {
1e691d
@@ -454,6 +464,44 @@ credentials_validate_existence (GoaKerberosIdentity *self,
1e691d
   return TRUE;
1e691d
 }
1e691d
 
1e691d
+static gboolean
1e691d
+snoop_preauth_identity_from_credentials (GoaKerberosIdentity  *self,
1e691d
+                                         krb5_creds           *credentials,
1e691d
+                                         char                **identity_source)
1e691d
+{
1e691d
+  GRegex *regex;
1e691d
+  GMatchInfo *match_info = NULL;
1e691d
+  gboolean identity_source_exposed = FALSE;
1e691d
+
1e691d
+  if (!krb5_is_config_principal (self->priv->kerberos_context, credentials->server))
1e691d
+    return FALSE;
1e691d
+
1e691d
+  regex = g_regex_new ("\"X509_user_identity\":\"(?P<identity_source>[^\"]*)\"",
1e691d
+                        G_REGEX_MULTILINE | G_REGEX_CASELESS | G_REGEX_RAW,
1e691d
+                        0,
1e691d
+                        NULL);
1e691d
+
1e691d
+  if (regex == NULL)
1e691d
+    return FALSE;
1e691d
+
1e691d
+  g_regex_match_full (regex, credentials->ticket.data, credentials->ticket.length, 0, 0, &match_info, NULL);
1e691d
+
1e691d
+  if (match_info != NULL && g_match_info_matches (match_info))
1e691d
+    {
1e691d
+      if (identity_source)
1e691d
+        {
1e691d
+          g_free (*identity_source);
1e691d
+          *identity_source = g_match_info_fetch_named (match_info, "identity_source");
1e691d
+        }
1e691d
+      identity_source_exposed = TRUE;
1e691d
+    }
1e691d
+
1e691d
+  g_match_info_free (match_info);
1e691d
+  g_regex_unref (regex);
1e691d
+
1e691d
+  return identity_source_exposed;
1e691d
+}
1e691d
+
1e691d
 static krb5_timestamp
1e691d
 get_current_time (GoaKerberosIdentity *self)
1e691d
 {
1e691d
@@ -565,6 +613,7 @@ credentials_are_expired (GoaKerberosIdentity *self,
1e691d
 
1e691d
 static VerificationLevel
1e691d
 verify_identity (GoaKerberosIdentity  *self,
1e691d
+                 char                **preauth_identity_source,
1e691d
                  GError              **error)
1e691d
 {
1e691d
   krb5_principal principal = NULL;
1e691d
@@ -627,6 +676,10 @@ verify_identity (GoaKerberosIdentity  *self,
1e691d
           else
1e691d
             verification_level = VERIFICATION_LEVEL_EXISTS;
1e691d
         }
1e691d
+      else
1e691d
+        {
1e691d
+          snoop_preauth_identity_from_credentials (self, &credentials, preauth_identity_source);
1e691d
+        }
1e691d
 
1e691d
       krb5_free_cred_contents (self->priv->kerberos_context, &credentials);
1e691d
 
1e691d
@@ -933,7 +986,7 @@ goa_kerberos_identity_initable_init (GInitable     *initable,
1e691d
 
1e691d
   verification_error = NULL;
1e691d
   self->priv->cached_verification_level =
1e691d
-    verify_identity (self, &verification_error);
1e691d
+    verify_identity (self, &self->priv->preauth_identity_source, &verification_error);
1e691d
 
1e691d
   switch (self->priv->cached_verification_level)
1e691d
     {
1e691d
@@ -1140,6 +1193,7 @@ gboolean
1e691d
 goa_kerberos_identity_sign_in (GoaKerberosIdentity     *self,
1e691d
                                const char              *principal_name,
1e691d
                                gconstpointer            initial_password,
1e691d
+                               const char              *preauth_source,
1e691d
                                GoaIdentitySignInFlags   flags,
1e691d
                                GoaIdentityInquiryFunc   inquiry_func,
1e691d
                                gpointer                 inquiry_data,
1e691d
@@ -1211,6 +1265,13 @@ goa_kerberos_identity_sign_in (GoaKerberosIdentity     *self,
1e691d
   if ((flags & GOA_IDENTITY_SIGN_IN_FLAGS_DISALLOW_RENEWAL) == 0)
1e691d
     krb5_get_init_creds_opt_set_renew_life (options, G_MAXINT);
1e691d
 
1e691d
+  if (preauth_source != NULL)
1e691d
+    {
1e691d
+      krb5_get_init_creds_opt_set_pa (self->priv->kerberos_context,
1e691d
+                                      options,
1e691d
+                                      "X509_user_identity", preauth_source);
1e691d
+    }
1e691d
+
1e691d
   /* Poke glibc in case the network changed
1e691d
    */
1e691d
   res_init ();
1e691d
@@ -1301,6 +1362,7 @@ goa_kerberos_identity_update (GoaKerberosIdentity *self,
1e691d
                               GoaKerberosIdentity *new_identity)
1e691d
 {
1e691d
   VerificationLevel verification_level;
1e691d
+  char *preauth_identity_source = NULL;
1e691d
 
1e691d
   if (self->priv->credentials_cache != NULL)
1e691d
     krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache);
1e691d
@@ -1313,13 +1375,18 @@ goa_kerberos_identity_update (GoaKerberosIdentity *self,
1e691d
   update_identifier (self, new_identity);
1e691d
   G_UNLOCK (identity_lock);
1e691d
 
1e691d
-  verification_level = verify_identity (self, NULL);
1e691d
+  verification_level = verify_identity (self, &preauth_identity_source, NULL);
1e691d
 
1e691d
   if (verification_level == VERIFICATION_LEVEL_SIGNED_IN)
1e691d
     reset_alarms (self);
1e691d
   else
1e691d
     clear_alarms (self);
1e691d
 
1e691d
+  G_LOCK (identity_lock);
1e691d
+  g_free (self->priv->preauth_identity_source);
1e691d
+  self->priv->preauth_identity_source = preauth_identity_source;
1e691d
+  G_UNLOCK (identity_lock);
1e691d
+
1e691d
   if (verification_level != self->priv->cached_verification_level)
1e691d
     {
1e691d
       if (self->priv->cached_verification_level == VERIFICATION_LEVEL_SIGNED_IN &&
1e691d
diff --git a/src/goaidentity/goakerberosidentity.h b/src/goaidentity/goakerberosidentity.h
1e691d
index 1e24796..8d2860a 100644
1e691d
--- a/src/goaidentity/goakerberosidentity.h
1e691d
+++ b/src/goaidentity/goakerberosidentity.h
1e691d
@@ -66,6 +66,7 @@ GoaIdentity *goa_kerberos_identity_new (krb5_context   kerberos_context,
1e691d
 gboolean goa_kerberos_identity_sign_in (GoaKerberosIdentity     *self,
1e691d
                                         const char              *principal_name,
1e691d
                                         gconstpointer            initial_password,
1e691d
+                                        const char              *preauth_source,
1e691d
                                         GoaIdentitySignInFlags   flags,
1e691d
                                         GoaIdentityInquiryFunc   inquiry_func,
1e691d
                                         gpointer                 inquiry_data,
1e691d
@@ -81,5 +82,6 @@ gboolean goa_kerberos_identity_erase (GoaKerberosIdentity *self,
1e691d
 
1e691d
 char *goa_kerberos_identity_get_principal_name (GoaKerberosIdentity *self);
1e691d
 char *goa_kerberos_identity_get_realm_name     (GoaKerberosIdentity *self);
1e691d
+char *goa_kerberos_identity_get_preauthentication_source     (GoaKerberosIdentity *self);
1e691d
 G_END_DECLS
1e691d
 #endif /* __GOA_KERBEROS_IDENTITY_H__ */
1e691d
diff --git a/src/goaidentity/goakerberosidentitymanager.c b/src/goaidentity/goakerberosidentitymanager.c
1e691d
index c9796ad..a1898c9 100644
1e691d
--- a/src/goaidentity/goakerberosidentitymanager.c
1e691d
+++ b/src/goaidentity/goakerberosidentitymanager.c
1e691d
@@ -81,6 +81,7 @@ typedef struct
1e691d
     {
1e691d
       const char *identifier;
1e691d
       gconstpointer initial_password;
1e691d
+      char *preauth_source;
1e691d
       GoaIdentitySignInFlags sign_in_flags;
1e691d
       GoaIdentityInquiry *inquiry;
1e691d
       GoaIdentityInquiryFunc inquiry_func;
1e691d
@@ -151,10 +152,14 @@ operation_free (Operation *operation)
1e691d
 
1e691d
   if (operation->type != OPERATION_TYPE_SIGN_IN &&
1e691d
       operation->type != OPERATION_TYPE_GET_IDENTITY)
1e691d
-    g_clear_object (&operation->identity);
1e691d
+    {
1e691d
+      g_clear_object (&operation->identity);
1e691d
+    }
1e691d
   else
1e691d
-    g_clear_pointer (&operation->identifier, g_free);
1e691d
-
1e691d
+    {
1e691d
+      g_clear_pointer (&operation->identifier, g_free);
1e691d
+      g_clear_pointer (&operation->preauth_source, g_free);
1e691d
+    }
1e691d
   g_clear_object (&operation->result);
1e691d
 
1e691d
   g_slice_free (Operation, operation);
1e691d
@@ -863,6 +868,7 @@ sign_in_identity (GoaKerberosIdentityManager *self,
1e691d
   if (!goa_kerberos_identity_sign_in (GOA_KERBEROS_IDENTITY (identity),
1e691d
                                       operation->identifier,
1e691d
                                       operation->initial_password,
1e691d
+                                      operation->preauth_source,
1e691d
                                       operation->sign_in_flags,
1e691d
                                       (GoaIdentityInquiryFunc)
1e691d
                                       on_kerberos_identity_inquiry,
1e691d
@@ -1178,6 +1184,7 @@ static void
1e691d
 goa_kerberos_identity_manager_sign_identity_in (GoaIdentityManager     *manager,
1e691d
                                                 const char             *identifier,
1e691d
                                                 gconstpointer           initial_password,
1e691d
+                                                const char             *preauth_source,
1e691d
                                                 GoaIdentitySignInFlags  flags,
1e691d
                                                 GoaIdentityInquiryFunc  inquiry_func,
1e691d
                                                 gpointer                inquiry_data,
1e691d
@@ -1201,6 +1208,7 @@ goa_kerberos_identity_manager_sign_identity_in (GoaIdentityManager     *manager,
1e691d
    * for duration of operation
1e691d
    */
1e691d
   operation->initial_password = initial_password;
1e691d
+  operation->preauth_source = g_strdup (preauth_source);
1e691d
   operation->sign_in_flags = flags;
1e691d
   operation->inquiry_func = inquiry_func;
1e691d
   operation->inquiry_data = inquiry_data;
1e691d
-- 
1e691d
2.1.0
1e691d