Blob Blame History Raw
From 3d9361b917ef923f39ba54835512171d83e457b7 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 22 Sep 2015 14:33:35 -0400
Subject: [PATCH 1/3] identity: consider ticket start time when calculating
 renewal time

Right now we try to renew the kerberos ticket at the midpoint between
when we first set up the renewal alarm and when the ticket expires.

Unfortunately, this doesn't work for kernel keyring based kerberos
tickets, since the alarms are reset on a regular interval (as part
of the polling process to check for updates, since kernel keyring
doesn't have changed notification). Since the alarms are reset
regularly, the midpoint converges toward the end of the ticket
lifetime.

Instead, we should consider the ticket start time, which remains
constant.  This commit tracks the ticket start time, and changes
the code renewal alarm to use the mid point between the start time
and expiration time of the ticket.
---
 src/goaidentity/goaidentity.c         |  7 +++++
 src/goaidentity/goakerberosidentity.c | 55 +++++++++++++++++++++++++++++------
 2 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/src/goaidentity/goaidentity.c b/src/goaidentity/goaidentity.c
index 2fc491b..2904e2a 100644
--- a/src/goaidentity/goaidentity.c
+++ b/src/goaidentity/goaidentity.c
@@ -13,60 +13,67 @@
  * 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-object.h>
 #include <glib/gi18n.h>
 
 #include "goaidentity.h"
 
 G_DEFINE_INTERFACE (GoaIdentity, goa_identity, G_TYPE_OBJECT);
 
 static void
 goa_identity_default_init (GoaIdentityInterface *interface)
 {
   g_object_interface_install_property (interface,
                                        g_param_spec_string ("identifier",
                                                             "identifier",
                                                             "identifier",
                                                             NULL, G_PARAM_READABLE));
   g_object_interface_install_property (interface,
                                        g_param_spec_boolean ("is-signed-in",
                                                              "Is signed in",
                                                              "Whether or not identity is currently signed in",
                                                              FALSE,
                                                              G_PARAM_READABLE));
   g_object_interface_install_property (interface,
+                                       g_param_spec_int64 ("start-timestamp",
+                                                           "Start Timestamp",
+                                                           "A timestamp of when the identities credentials first became valid",
+                                                           -1,
+                                                           G_MAXINT64,
+                                                           -1, G_PARAM_READABLE));
+  g_object_interface_install_property (interface,
                                        g_param_spec_int64 ("expiration-timestamp",
                                                            "Expiration Timestamp",
                                                            "A timestamp of when the identities credentials expire",
                                                            -1,
                                                            G_MAXINT64,
                                                            -1, G_PARAM_READABLE));
 }
 
 GQuark
 goa_identity_error_quark (void)
 {
   static GQuark error_quark = 0;
 
   if (error_quark == 0)
     {
       error_quark = g_quark_from_static_string ("goa-identity-error");
     }
 
   return error_quark;
 }
 
 const char *
 goa_identity_get_identifier (GoaIdentity *self)
 {
   return GOA_IDENTITY_GET_IFACE (self)->get_identifier (self);
 }
 
 gboolean
 goa_identity_is_signed_in (GoaIdentity *self)
 {
diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c
index 4370a09..6865535 100644
--- a/src/goaidentity/goakerberosidentity.c
+++ b/src/goaidentity/goakerberosidentity.c
@@ -22,86 +22,89 @@
 #include "goakerberosidentity.h"
 #include "goakerberosidentityinquiry.h"
 #include "goaalarm.h"
 
 #include <netinet/in.h>
 #include <arpa/nameser.h>
 #include <resolv.h>
 
 #include <string.h>
 #include <glib/gi18n.h>
 #include <gio/gio.h>
 
 typedef enum
 {
   VERIFICATION_LEVEL_UNVERIFIED,
   VERIFICATION_LEVEL_ERROR,
   VERIFICATION_LEVEL_EXISTS,
   VERIFICATION_LEVEL_SIGNED_IN
 } VerificationLevel;
 
 struct _GoaKerberosIdentityPrivate
 {
   krb5_context kerberos_context;
   krb5_ccache  credentials_cache;
 
   char *identifier;
   guint identifier_idle_id;
 
   char *preauth_identity_source;
 
+  krb5_timestamp start_time;
+  guint          start_time_idle_id;
   krb5_timestamp expiration_time;
   guint          expiration_time_idle_id;
 
   GoaAlarm     *expiration_alarm;
   GoaAlarm     *expiring_alarm;
   GoaAlarm     *renewal_alarm;
 
   VerificationLevel cached_verification_level;
   guint             is_signed_in_idle_id;
 };
 
 enum
 {
   EXPIRING,
   EXPIRED,
   UNEXPIRED,
   NEEDS_RENEWAL,
   NEEDS_REFRESH,
   NUMBER_OF_SIGNALS,
 };
 
 enum
 {
   PROP_0,
   PROP_IDENTIFIER,
   PROP_IS_SIGNED_IN,
+  PROP_START_TIMESTAMP,
   PROP_EXPIRATION_TIMESTAMP
 };
 
 static guint signals[NUMBER_OF_SIGNALS] = { 0 };
 
 static void identity_interface_init (GoaIdentityInterface *interface);
 static void initable_interface_init (GInitableIface *interface);
 static void reset_alarms (GoaKerberosIdentity *self);
 static void clear_alarms (GoaKerberosIdentity *self);
 static gboolean goa_kerberos_identity_is_signed_in (GoaIdentity *identity);
 static void set_error_from_krb5_error_code (GoaKerberosIdentity  *self,
                                             GError              **error,
                                             gint                  code,
                                             krb5_error_code       error_code,
                                             const char           *format,
                                             ...);
 
 G_LOCK_DEFINE_STATIC (identity_lock);
 
 G_DEFINE_TYPE_WITH_CODE (GoaKerberosIdentity,
                          goa_kerberos_identity,
                          G_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
                                                 initable_interface_init)
                          G_IMPLEMENT_INTERFACE (GOA_TYPE_IDENTITY,
                                                 identity_interface_init));
 static void
 goa_kerberos_identity_dispose (GObject *object)
 {
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object);
@@ -121,60 +124,65 @@ goa_kerberos_identity_finalize (GObject *object)
 {
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object);
 
   g_free (self->priv->identifier);
 
   if (self->priv->credentials_cache != NULL)
     krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache);
 
   G_OBJECT_CLASS (goa_kerberos_identity_parent_class)->finalize (object);
 }
 
 static void
 goa_kerberos_identity_get_property (GObject    *object,
                                     guint       property_id,
                                     GValue     *value,
                                     GParamSpec *param_spec)
 {
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (object);
 
   switch (property_id)
     {
     case PROP_IDENTIFIER:
       G_LOCK (identity_lock);
       g_value_set_string (value, self->priv->identifier);
       G_UNLOCK (identity_lock);
       break;
     case PROP_IS_SIGNED_IN:
       g_value_set_boolean (value,
                            goa_kerberos_identity_is_signed_in (GOA_IDENTITY (self)));
       break;
+    case PROP_START_TIMESTAMP:
+      G_LOCK (identity_lock);
+      g_value_set_int64 (value, (gint64) self->priv->start_time);
+      G_UNLOCK (identity_lock);
+      break;
     case PROP_EXPIRATION_TIMESTAMP:
       G_LOCK (identity_lock);
       g_value_set_int64 (value, (gint64) self->priv->expiration_time);
       G_UNLOCK (identity_lock);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, param_spec);
       break;
     }
 }
 
 static void
 goa_kerberos_identity_class_init (GoaKerberosIdentityClass *klass)
 {
   GObjectClass *object_class;
 
   object_class = G_OBJECT_CLASS (klass);
 
   object_class->dispose = goa_kerberos_identity_dispose;
   object_class->finalize = goa_kerberos_identity_finalize;
   object_class->get_property = goa_kerberos_identity_get_property;
 
   g_type_class_add_private (klass, sizeof (GoaKerberosIdentityPrivate));
 
   signals[EXPIRING] = g_signal_new ("expiring",
                                     G_TYPE_FROM_CLASS (klass),
                                     G_SIGNAL_RUN_LAST,
                                     0,
                                     NULL,
                                     NULL,
@@ -194,60 +202,63 @@ goa_kerberos_identity_class_init (GoaKerberosIdentityClass *klass)
                                      G_TYPE_FROM_CLASS (klass),
                                      G_SIGNAL_RUN_LAST,
                                      0,
                                      NULL,
                                      NULL,
                                      NULL,
                                      G_TYPE_NONE,
                                      0);
   signals[NEEDS_RENEWAL] = g_signal_new ("needs-renewal",
                                          G_TYPE_FROM_CLASS (klass),
                                          G_SIGNAL_RUN_LAST,
                                          0,
                                          NULL,
                                          NULL,
                                          NULL,
                                          G_TYPE_NONE,
                                          0);
   signals[NEEDS_REFRESH] = g_signal_new ("needs-refresh",
                                          G_TYPE_FROM_CLASS (klass),
                                          G_SIGNAL_RUN_LAST,
                                          0,
                                          NULL,
                                          NULL,
                                          NULL,
                                          G_TYPE_NONE,
                                          0);
 
   g_object_class_override_property (object_class, PROP_IDENTIFIER, "identifier");
   g_object_class_override_property (object_class, PROP_IS_SIGNED_IN, "is-signed-in");
   g_object_class_override_property (object_class,
+                                    PROP_START_TIMESTAMP,
+                                    "start-timestamp");
+  g_object_class_override_property (object_class,
                                     PROP_EXPIRATION_TIMESTAMP,
                                     "expiration-timestamp");
 
 }
 
 static char *
 get_identifier (GoaKerberosIdentity  *self,
                 GError              **error)
 {
   krb5_principal principal;
   krb5_error_code error_code;
   char *unparsed_name;
   char *identifier = NULL;
 
   if (self->priv->credentials_cache == NULL)
     return NULL;
 
   error_code = krb5_cc_get_principal (self->priv->kerberos_context,
                                       self->priv->credentials_cache,
                                       &principal);
 
   if (error_code != 0)
     {
       if (error_code == KRB5_CC_END)
         {
           set_error_from_krb5_error_code (self,
                                           error,
                                           GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE,
                                           error_code,
                                           _
@@ -546,207 +557,233 @@ on_notify_queued (NotifyRequest *request)
 
   return FALSE;
 }
 
 static void
 queue_notify (GoaKerberosIdentity *self,
               guint               *idle_id,
               const char          *property_name)
 {
   NotifyRequest *request;
 
   if (*idle_id != 0)
     {
       return;
     }
 
   request = g_slice_new0 (NotifyRequest);
   request->self = g_object_ref (self);
   request->idle_id = idle_id;
   request->property_name = property_name;
 
   *idle_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE,
                               (GSourceFunc)
                               on_notify_queued,
                               request,
                               (GDestroyNotify)
                               clear_idle_id);
 }
 
 static void
+set_start_time (GoaKerberosIdentity *self,
+                krb5_timestamp       start_time)
+{
+  G_LOCK (identity_lock);
+  if (self->priv->start_time != start_time)
+    {
+      self->priv->start_time = start_time;
+      G_UNLOCK (identity_lock);
+      queue_notify (self,
+                    &self->priv->start_time_idle_id,
+                    "start-timestamp");
+      G_LOCK (identity_lock);
+    }
+  G_UNLOCK (identity_lock);
+}
+
+static void
 set_expiration_time (GoaKerberosIdentity *self,
                      krb5_timestamp       expiration_time)
 {
   G_LOCK (identity_lock);
   if (self->priv->expiration_time != expiration_time)
     {
       self->priv->expiration_time = expiration_time;
       G_UNLOCK (identity_lock);
       queue_notify (self,
                     &self->priv->expiration_time_idle_id,
                     "expiration-timestamp");
       G_LOCK (identity_lock);
     }
   G_UNLOCK (identity_lock);
 }
 
 static gboolean
 credentials_are_expired (GoaKerberosIdentity *self,
                          krb5_creds          *credentials,
+                         krb5_timestamp      *start_time,
                          krb5_timestamp      *expiration_time)
 {
   krb5_timestamp current_time;
 
   current_time = get_current_time (self);
 
   G_LOCK (identity_lock);
+  if (self->priv->start_time == 0)
+    *start_time = credentials->times.starttime;
+  else
+    *start_time = MIN (self->priv->start_time,
+                       credentials->times.starttime);
   *expiration_time = MAX (credentials->times.endtime,
                           self->priv->expiration_time);
   G_UNLOCK (identity_lock);
 
-  if (credentials->times.endtime <= current_time)
+  if (current_time < credentials->times.starttime ||
+      credentials->times.endtime <= current_time)
     {
       return TRUE;
     }
 
   return FALSE;
 }
 
 static VerificationLevel
 verify_identity (GoaKerberosIdentity  *self,
                  char                **preauth_identity_source,
                  GError              **error)
 {
   krb5_principal principal = NULL;
   krb5_cc_cursor cursor;
   krb5_creds credentials;
   krb5_error_code error_code;
+  krb5_timestamp start_time = 0;
   krb5_timestamp expiration_time = 0;
   VerificationLevel verification_level = VERIFICATION_LEVEL_UNVERIFIED;
 
   if (self->priv->credentials_cache == NULL)
     goto out;
 
   error_code = krb5_cc_get_principal (self->priv->kerberos_context,
                                       self->priv->credentials_cache,
                                       &principal);
 
   if (error_code != 0)
     {
       if (error_code == KRB5_CC_END || error_code == KRB5_FCC_NOFILE)
         goto out;
 
       set_error_from_krb5_error_code (self,
                                       error,
                                       GOA_IDENTITY_ERROR_NOT_FOUND,
                                       error_code,
                                       _("Could not find identity in "
                                         "credential cache: %k"));
       verification_level = VERIFICATION_LEVEL_ERROR;
       goto out;
     }
 
   error_code = krb5_cc_start_seq_get (self->priv->kerberos_context,
                                       self->priv->credentials_cache, &cursor);
   if (error_code != 0)
     {
       set_error_from_krb5_error_code (self,
                                       error,
                                       GOA_IDENTITY_ERROR_CREDENTIALS_UNAVAILABLE,
                                       error_code,
                                       _("Could not find identity "
                                         "credentials in cache: %k"));
 
       verification_level = VERIFICATION_LEVEL_ERROR;
       goto out;
     }
 
   verification_level = VERIFICATION_LEVEL_UNVERIFIED;
 
   error_code = krb5_cc_next_cred (self->priv->kerberos_context,
                                   self->priv->credentials_cache,
                                   &cursor,
                                   &credentials);
 
   while (error_code == 0)
     {
       if (credentials_validate_existence (self, principal, &credentials))
         {
-          if (!credentials_are_expired (self, &credentials, &expiration_time))
+          if (!credentials_are_expired (self, &credentials, &start_time, &expiration_time))
             verification_level = VERIFICATION_LEVEL_SIGNED_IN;
           else
             verification_level = VERIFICATION_LEVEL_EXISTS;
         }
       else
         {
           snoop_preauth_identity_from_credentials (self, &credentials, preauth_identity_source);
         }
 
       krb5_free_cred_contents (self->priv->kerberos_context, &credentials);
 
       error_code = krb5_cc_next_cred (self->priv->kerberos_context,
                                       self->priv->credentials_cache,
                                       &cursor,
                                       &credentials);
     }
 
   if (error_code != KRB5_CC_END)
     {
       verification_level = VERIFICATION_LEVEL_ERROR;
 
       set_error_from_krb5_error_code (self,
                                       error,
                                       GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS,
                                       error_code,
                                       _("Could not sift through identity "
                                         "credentials in cache: %k"));
       goto end_sequence;
     }
 
  end_sequence:
   error_code = krb5_cc_end_seq_get (self->priv->kerberos_context,
                                     self->priv->credentials_cache,
                                     &cursor);
 
   if (error_code != 0)
     {
       verification_level = VERIFICATION_LEVEL_ERROR;
 
       set_error_from_krb5_error_code (self,
                                       error,
                                       GOA_IDENTITY_ERROR_ENUMERATING_CREDENTIALS,
                                       error_code,
                                       _("Could not finish up sifting through "
                                         "identity credentials in cache: %k"));
       goto out;
     }
 out:
+  set_start_time (self, start_time);
   set_expiration_time (self, expiration_time);
 
   if (principal != NULL)
     krb5_free_principal (self->priv->kerberos_context, principal);
   return verification_level;
 }
 
 static gboolean
 goa_kerberos_identity_is_signed_in (GoaIdentity *identity)
 {
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (identity);
   gboolean is_signed_in = FALSE;
 
   G_LOCK (identity_lock);
   if (self->priv->cached_verification_level == VERIFICATION_LEVEL_SIGNED_IN)
     is_signed_in = TRUE;
   G_UNLOCK (identity_lock);
 
   return is_signed_in;
 }
 
 static void
 identity_interface_init (GoaIdentityInterface *interface)
 {
   interface->get_identifier = goa_kerberos_identity_get_identifier;
   interface->is_signed_in = goa_kerberos_identity_is_signed_in;
 }
 
 static void
 on_expiration_alarm_fired (GoaAlarm            *alarm,
@@ -895,90 +932,90 @@ connect_alarm_signals (GoaKerberosIdentity *self)
 {
   g_signal_connect (G_OBJECT (self->priv->renewal_alarm),
                     "fired",
                     G_CALLBACK (on_renewal_alarm_fired),
                     self);
   g_signal_connect (G_OBJECT (self->priv->renewal_alarm),
                     "rearmed",
                     G_CALLBACK (on_renewal_alarm_rearmed),
                     self);
   g_signal_connect (G_OBJECT (self->priv->expiring_alarm),
                     "fired",
                     G_CALLBACK (on_expiring_alarm_fired),
                     self);
   g_signal_connect (G_OBJECT (self->priv->expiring_alarm),
                     "rearmed",
                     G_CALLBACK (on_expiring_alarm_rearmed),
                     self);
   g_signal_connect (G_OBJECT (self->priv->expiration_alarm),
                     "fired",
                     G_CALLBACK (on_expiration_alarm_fired),
                     self);
   g_signal_connect (G_OBJECT (self->priv->expiration_alarm),
                     "rearmed",
                     G_CALLBACK (on_expiration_alarm_rearmed),
                     self);
 }
 
 static void
 reset_alarms (GoaKerberosIdentity *self)
 {
-  GDateTime *now;
+  GDateTime *start_time;
   GDateTime *expiration_time;
   GDateTime *expiring_time;
   GDateTime *renewal_time;
-  GTimeSpan time_span_until_expiration;
+  GTimeSpan  lifespan;
 
-  now = g_date_time_new_now_local ();
   G_LOCK (identity_lock);
+  start_time = g_date_time_new_from_unix_local (self->priv->start_time);
   expiration_time = g_date_time_new_from_unix_local (self->priv->expiration_time);
   G_UNLOCK (identity_lock);
-  time_span_until_expiration = g_date_time_difference (expiration_time, now);
-  g_date_time_unref (now);
+
+  lifespan = g_date_time_difference (expiration_time, start_time);
 
   /* Let the user reauthenticate 10 min before expiration */
   expiring_time = g_date_time_add_minutes (expiration_time, -10);
 
   /* Try to quietly auto-renew halfway through so in ideal configurations
    * the ticket is never more than halfway to expired
    */
-  renewal_time = g_date_time_add (expiration_time,
-                                  -(time_span_until_expiration / 2));
+  renewal_time = g_date_time_add (expiration_time, -(lifespan / 2));
 
   disconnect_alarm_signals (self);
 
   reset_alarm (self, &self->priv->renewal_alarm, renewal_time);
   reset_alarm (self, &self->priv->expiring_alarm, expiring_time);
   reset_alarm (self, &self->priv->expiration_alarm, expiration_time);
 
   g_date_time_unref (renewal_time);
   g_date_time_unref (expiring_time);
+  g_date_time_unref (start_time);
   g_date_time_unref (expiration_time);
   connect_alarm_signals (self);
 }
 
 static void
 clear_alarms (GoaKerberosIdentity *self)
 {
   disconnect_alarm_signals (self);
   clear_alarm_and_unref_on_idle (self, &self->priv->renewal_alarm);
   clear_alarm_and_unref_on_idle (self, &self->priv->expiring_alarm);
   clear_alarm_and_unref_on_idle (self, &self->priv->expiration_alarm);
 }
 
 static gboolean
 goa_kerberos_identity_initable_init (GInitable     *initable,
                                      GCancellable  *cancellable,
                                      GError       **error)
 {
   GoaKerberosIdentity *self = GOA_KERBEROS_IDENTITY (initable);
   GError *verification_error;
 
   if (g_cancellable_set_error_if_cancelled (cancellable, error))
     return FALSE;
 
   if (self->priv->identifier == NULL)
     {
       self->priv->identifier = get_identifier (self, error);
 
       if (self->priv->identifier != NULL)
         queue_notify (self, &self->priv->identifier_idle_id, "identifier");
-- 
2.5.0


From 57757628e01dcd1d6ce9855bdad70d5f69757157 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 22 Sep 2015 14:41:05 -0400
Subject: [PATCH 2/3] identity: don't ever nullify identifier

credentials stored in the kernel keyring disappear after they expire.
This is is different from other credential caches, which hang around
but maintain an expired timestamp until kdestroy. Because the credentials
vanish, trying to read the principal from an previously existing credential
cache, will yield NULL.

This can lead to a crash in goa which never expects the identifier of an
identity object to be NULL.

This commit makes sure we retain the old identifier in the event the
credential cache gets wiped.
---
 src/goaidentity/goakerberosidentity.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/goaidentity/goakerberosidentity.c b/src/goaidentity/goakerberosidentity.c
index 6865535..f43978d 100644
--- a/src/goaidentity/goakerberosidentity.c
+++ b/src/goaidentity/goakerberosidentity.c
@@ -1355,61 +1355,61 @@ goa_kerberos_identity_sign_in (GoaKerberosIdentity     *self,
       goto done;
     }
 
   if (destroy_notify)
     destroy_notify (inquiry_data);
   sign_in_operation_free (operation);
 
   if (!goa_kerberos_identity_update_credentials (self,
                                                  principal,
                                                  &new_credentials,
                                                  error))
     {
       krb5_free_principal (self->priv->kerberos_context, principal);
       goto done;
     }
   krb5_free_principal (self->priv->kerberos_context, principal);
 
   g_debug ("GoaKerberosIdentity: identity signed in");
   signed_in = TRUE;
 done:
 
   return signed_in;
 }
 
 static void
 update_identifier (GoaKerberosIdentity *self, GoaKerberosIdentity *new_identity)
 {
   char *new_identifier;
 
   new_identifier = get_identifier (self, NULL);
-  if (g_strcmp0 (self->priv->identifier, new_identifier) != 0)
+  if (g_strcmp0 (self->priv->identifier, new_identifier) != 0 && new_identifier != NULL)
     {
       g_free (self->priv->identifier);
       self->priv->identifier = new_identifier;
       queue_notify (self, &self->priv->identifier_idle_id, "identifier");
     }
   else
     {
       g_free (new_identifier);
     }
 }
 
 void
 goa_kerberos_identity_update (GoaKerberosIdentity *self,
                               GoaKerberosIdentity *new_identity)
 {
   VerificationLevel verification_level;
   char *preauth_identity_source = NULL;
 
   if (self->priv->credentials_cache != NULL)
     krb5_cc_close (self->priv->kerberos_context, self->priv->credentials_cache);
 
   krb5_cc_dup (new_identity->priv->kerberos_context,
                new_identity->priv->credentials_cache,
                &self->priv->credentials_cache);
 
   G_LOCK (identity_lock);
   update_identifier (self, new_identity);
   G_UNLOCK (identity_lock);
 
   verification_level = verify_identity (self, &preauth_identity_source, NULL);
-- 
2.5.0


From 8d8a923530402fef8dd04b5b4efd349c45118e13 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 22 Sep 2015 14:38:29 -0400
Subject: [PATCH 3/3] identity: don't ignore almost all renewal requests

There's a bug in the code where we ignore all renewal requests for
objects we already know about.

This means we'll only ever honor renewal requests that happen almost
immediately after start up.

This commit fixes the bug, so the only renewal requests that aren't
honored, are those that have been specifically disabled by the user.
This was clearly the original intention of the buggy code.
---
 src/goaidentity/goaidentityservice.c | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/goaidentity/goaidentityservice.c b/src/goaidentity/goaidentityservice.c
index 6b6225a..bb5d3a7 100644
--- a/src/goaidentity/goaidentityservice.c
+++ b/src/goaidentity/goaidentityservice.c
@@ -714,70 +714,71 @@ static void
 on_identity_renewed (GoaIdentityManager *manager,
                      GAsyncResult       *result,
                      GoaIdentityService *self)
 {
   GError *error;
 
   error = NULL;
   goa_identity_manager_renew_identity_finish (manager, result, &error);
 
   if (error != NULL)
     {
       g_debug ("GoaIdentityService: could not renew identity: %s",
                error->message);
       g_error_free (error);
       return;
     }
 
   g_debug ("GoaIdentityService: identity renewed");
 }
 
 static void
 on_identity_needs_renewal (GoaIdentityManager *identity_manager,
                            GoaIdentity        *identity,
                            GoaIdentityService *self)
 {
   const char *principal;
   GoaObject  *object;
 
   principal = goa_identity_get_identifier (identity);
 
-  g_debug ("GoaIdentityService: identity %s needs renewal", principal);
-
   object = find_object_with_principal (self, principal, TRUE);
 
-  if (object != NULL)
+  if (object != NULL && should_ignore_object (self, object))
     {
-      should_ignore_object (self, object);
+      g_debug ("GoaIdentityService: ignoring identity %s that says it needs renewal", principal);
+
       return;
     }
 
+  g_debug ("GoaIdentityService: identity %s needs renewal", principal);
+
   goa_identity_manager_renew_identity (GOA_IDENTITY_MANAGER
                                        (self->priv->identity_manager),
                                        identity,
                                        NULL,
                                        (GAsyncReadyCallback)
                                        on_identity_renewed,
                                        self);
 }
 
 static void
 on_identity_signed_in (GoaIdentityManager *manager,
                        GAsyncResult       *result,
                        GSimpleAsyncResult *operation_result)
 {
   GError *error;
   GoaIdentity *identity;
 
   error = NULL;
   identity = goa_identity_manager_sign_identity_in_finish (manager, result, &error);
 
   if (error != NULL)
     {
       g_debug ("GoaIdentityService: could not sign in identity: %s",
                error->message);
       g_simple_async_result_take_error (operation_result, error);
     }
   else
     {
       g_simple_async_result_set_op_res_gpointer (operation_result,
                                                  g_object_ref (identity),
-- 
2.5.0