~ubuntu-branches/ubuntu/saucy/gnome-online-accounts/saucy

« back to all changes in this revision

Viewing changes to src/goabackend/goakerberosprovider.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2012-08-20 22:37:44 UTC
  • mfrom: (1.1.15)
  • Revision ID: package-import@ubuntu.com-20120820223744-ndi1s9124mef09ak
Tags: 3.5.90-0ubuntu1
* New upstream release.
* debian/control.in:
  - Build-depend on krb5-config, libgcr-3-dev, and libkrb5-dev
* debian/rules:
  - Enable Kerberos provider
* debian/libgoa-1.0-0.symbols: Added new symbols

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 
2
/*
 
3
 * Copyright (C) 2012 Red Hat, Inc.
 
4
 *
 
5
 * This library is free software; you can redistribute it and/or
 
6
 * modify it under the terms of the GNU Lesser General Public
 
7
 * License as published by the Free Software Foundation; either
 
8
 * version 2 of the License, or (at your option) any later version.
 
9
 *
 
10
 * This library is distributed in the hope that it will be useful,
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
13
 * Lesser General Public License for more details.
 
14
 *
 
15
 * You should have received a copy of the GNU Lesser General
 
16
 * Public License along with this library; if not, write to the
 
17
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 
18
 * Boston, MA 02111-1307, USA.
 
19
 *
 
20
 * Author: Ray Strode <rstrode@redhat.com>
 
21
 * Based on code from Debarshi Ray <debarshir@gnome.org>
 
22
 *                    Stef Walter <stefw@gnome.org>
 
23
 */
 
24
 
 
25
#include "config.h"
 
26
#include <glib/gi18n-lib.h>
 
27
 
 
28
#include "goalogging.h"
 
29
#include "goaprovider.h"
 
30
#include "goakerberosprovider.h"
 
31
#include "goaeditablelabel.h"
 
32
#include "goautils.h"
 
33
#include "goaidentity.h"
 
34
 
 
35
#include <gcr/gcr.h>
 
36
 
 
37
#include "org.gnome.Identity.h"
 
38
 
 
39
/**
 
40
 * GoaKerberosProvider:
 
41
 *
 
42
 * The #GoaKerberosProvider structure contains only private request and should
 
43
 * only be accessed using the provided API.
 
44
 */
 
45
struct _GoaKerberosProvider
 
46
{
 
47
  /*< private >*/
 
48
  GoaProvider parent_instance;
 
49
  GoaIdentityServiceManager *identity_manager;
 
50
  GDBusObjectManager *object_manager;
 
51
};
 
52
 
 
53
typedef struct _GoaKerberosProviderClass GoaKerberosProviderClass;
 
54
 
 
55
struct _GoaKerberosProviderClass
 
56
{
 
57
  GoaProviderClass parent_class;
 
58
};
 
59
 
 
60
/**
 
61
 * SECTION:goakerberosprovider
 
62
 * @title: GoaKerberosProvider
 
63
 * @short_description: A provider for enterperise identity servers
 
64
 *
 
65
 * #GoaKerberosProvider is used to access enterperise identity servers.
 
66
 */
 
67
 
 
68
G_DEFINE_TYPE_WITH_CODE (GoaKerberosProvider, goa_kerberos_provider, GOA_TYPE_PROVIDER,
 
69
                         g_io_extension_point_implement (GOA_PROVIDER_EXTENSION_POINT_NAME,
 
70
                                                         g_define_type_id,
 
71
                                                         "kerberos",
 
72
                                                         0));
 
73
 
 
74
static const gchar *
 
75
get_provider_type (GoaProvider *provider)
 
76
{
 
77
  return "kerberos";
 
78
}
 
79
 
 
80
static gchar *
 
81
get_provider_name (GoaProvider *provider, GoaObject *object)
 
82
{
 
83
  return g_strdup(_("Enterprise Login (Kerberos)"));
 
84
}
 
85
 
 
86
typedef struct
 
87
{
 
88
  GtkDialog *dialog;
 
89
  GMainLoop *loop;
 
90
 
 
91
  GtkWidget *cluebar;
 
92
  GtkWidget *cluebar_label;
 
93
  GtkWidget *spinner;
 
94
 
 
95
  GtkWidget *username;
 
96
  GtkWidget *realm_entry;
 
97
  GtkWidget *realm_combo_box;
 
98
  GtkListStore *realm_store;
 
99
 
 
100
  guint      interface_added_id;
 
101
 
 
102
  gboolean realm_chosen;
 
103
 
 
104
  gchar *account_object_path;
 
105
 
 
106
  GError *error;
 
107
} SignInRequest;
 
108
 
 
109
static void
 
110
translate_error (GError **error)
 
111
{
 
112
  if (!g_dbus_error_is_remote_error (*error))
 
113
    return;
 
114
 
 
115
  g_dbus_error_strip_remote_error (*error);
 
116
}
 
117
 
 
118
static void
 
119
on_identity_signed_in (GoaIdentityServiceManager *manager,
 
120
                       GAsyncResult              *result,
 
121
                       GSimpleAsyncResult        *operation_result)
 
122
{
 
123
  gboolean  signed_in;
 
124
  GError   *error;
 
125
  char     *identity_object_path;
 
126
 
 
127
  error = NULL;
 
128
  signed_in = goa_identity_service_manager_call_sign_in_finish (manager,
 
129
                                                                &identity_object_path,
 
130
                                                                result,
 
131
                                                                &error);
 
132
 
 
133
  if (!signed_in)
 
134
    {
 
135
      translate_error (&error);
 
136
 
 
137
      if (g_error_matches (error,
 
138
                           G_IO_ERROR,
 
139
                           G_IO_ERROR_CANCELLED))
 
140
        {
 
141
          g_clear_error (&error);
 
142
          g_set_error_literal (&error,
 
143
                               GOA_ERROR,
 
144
                               GOA_ERROR_DIALOG_DISMISSED,
 
145
                               "");
 
146
        }
 
147
 
 
148
      g_simple_async_result_take_error (operation_result, error);
 
149
      g_simple_async_result_complete_in_idle (operation_result);
 
150
      g_object_unref (operation_result);
 
151
      return;
 
152
    }
 
153
 
 
154
  g_simple_async_result_set_op_res_gpointer (operation_result,
 
155
                                             g_strdup (identity_object_path),
 
156
                                             (GDestroyNotify)
 
157
                                             g_free);
 
158
  g_simple_async_result_complete_in_idle (operation_result);
 
159
  g_object_unref (operation_result);
 
160
}
 
161
 
 
162
static void
 
163
on_identity_manager_ensured (GoaKerberosProvider *self,
 
164
                             GAsyncResult        *result,
 
165
                             GSimpleAsyncResult  *operation_result)
 
166
{
 
167
  GoaIdentityServiceManager *manager;
 
168
  GError             *error;
 
169
 
 
170
  error = NULL;
 
171
  manager = goa_identity_service_manager_proxy_new_for_bus_finish (result, &error);
 
172
  if (manager == NULL)
 
173
    {
 
174
      translate_error (&error);
 
175
      g_simple_async_result_take_error (operation_result, error);
 
176
      g_simple_async_result_complete_in_idle (operation_result);
 
177
      g_object_unref (operation_result);
 
178
      return;
 
179
    }
 
180
 
 
181
  g_simple_async_result_set_op_res_gpointer (operation_result,
 
182
                                             g_object_ref (manager),
 
183
                                             (GDestroyNotify)
 
184
                                             g_object_unref);
 
185
  g_simple_async_result_complete_in_idle (operation_result);
 
186
  g_object_unref (operation_result);
 
187
}
 
188
 
 
189
static void
 
190
ensure_identity_manager (GoaKerberosProvider *self,
 
191
                         GCancellable        *cancellable,
 
192
                         GAsyncReadyCallback  callback,
 
193
                         gpointer             user_data)
 
194
{
 
195
  GSimpleAsyncResult *operation_result;
 
196
 
 
197
  operation_result = g_simple_async_result_new (G_OBJECT (self),
 
198
                                                callback,
 
199
                                                user_data,
 
200
                                                ensure_identity_manager);
 
201
  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
 
202
 
 
203
  g_object_set_data (G_OBJECT (operation_result),
 
204
                     "cancellable",
 
205
                     cancellable);
 
206
 
 
207
  if (self->identity_manager != NULL)
 
208
    {
 
209
      g_simple_async_result_set_op_res_gpointer (operation_result,
 
210
                                                 g_object_ref (self->identity_manager),
 
211
                                                 (GDestroyNotify)
 
212
                                                 g_object_unref);
 
213
      g_simple_async_result_complete_in_idle (operation_result);
 
214
      g_object_unref (operation_result);
 
215
      return;
 
216
    }
 
217
 
 
218
  goa_identity_service_manager_proxy_new_for_bus (G_BUS_TYPE_SESSION,
 
219
                                                  G_DBUS_PROXY_FLAGS_NONE,
 
220
                                                  "org.gnome.Identity",
 
221
                                                  "/org/gnome/Identity/Manager",
 
222
                                                  cancellable,
 
223
                                                  (GAsyncReadyCallback)
 
224
                                                  on_identity_manager_ensured,
 
225
                                                  operation_result);
 
226
}
 
227
 
 
228
static void
 
229
on_object_manager_ensured (GoaKerberosProvider *self,
 
230
                           GAsyncResult        *result,
 
231
                           GSimpleAsyncResult  *operation_result)
 
232
{
 
233
  GDBusObjectManager *manager;
 
234
  GError *error;
 
235
 
 
236
  error = NULL;
 
237
  manager = goa_identity_service_object_manager_client_new_for_bus_finish (result, &error);
 
238
  if (manager == NULL)
 
239
    {
 
240
      translate_error (&error);
 
241
      g_simple_async_result_take_error (operation_result, error);
 
242
      g_simple_async_result_complete_in_idle (operation_result);
 
243
      g_object_unref (operation_result);
 
244
      return;
 
245
    }
 
246
 
 
247
  g_simple_async_result_set_op_res_gpointer (operation_result,
 
248
                                             g_object_ref (manager),
 
249
                                             (GDestroyNotify)
 
250
                                             g_object_unref);
 
251
  g_simple_async_result_complete_in_idle (operation_result);
 
252
  g_object_unref (operation_result);
 
253
}
 
254
 
 
255
static void
 
256
ensure_object_manager (GoaKerberosProvider *self,
 
257
                       GCancellable        *cancellable,
 
258
                       GAsyncReadyCallback  callback,
 
259
                       gpointer             user_data)
 
260
{
 
261
  GSimpleAsyncResult *operation_result;
 
262
 
 
263
  operation_result = g_simple_async_result_new (G_OBJECT (self),
 
264
                                                callback,
 
265
                                                user_data,
 
266
                                                ensure_object_manager);
 
267
  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
 
268
 
 
269
  g_object_set_data (G_OBJECT (operation_result),
 
270
                     "cancellable",
 
271
                     cancellable);
 
272
 
 
273
  if (self->object_manager != NULL)
 
274
    {
 
275
      g_simple_async_result_set_op_res_gpointer (operation_result,
 
276
                                                 g_object_ref (self->object_manager),
 
277
                                                 (GDestroyNotify)
 
278
                                                 g_object_unref);
 
279
      g_simple_async_result_complete_in_idle (operation_result);
 
280
      g_object_unref (operation_result);
 
281
      return;
 
282
    }
 
283
  goa_identity_service_object_manager_client_new_for_bus (G_BUS_TYPE_SESSION,
 
284
                                                          G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
 
285
                                                          "org.gnome.Identity",
 
286
                                                          "/org/gnome/Identity",
 
287
                                                          cancellable,
 
288
                                                          (GAsyncReadyCallback)
 
289
                                                          on_object_manager_ensured,
 
290
                                                          operation_result);
 
291
}
 
292
 
 
293
static void
 
294
on_secret_keys_exchanged_for_sign_in (GoaKerberosProvider *self,
 
295
                                      GAsyncResult        *result,
 
296
                                      GSimpleAsyncResult  *operation_result)
 
297
{
 
298
  const char       *identifier;
 
299
  const char       *password;
 
300
  GCancellable     *cancellable;
 
301
  GError           *error;
 
302
  GVariantBuilder   details;
 
303
 
 
304
  error = NULL;
 
305
 
 
306
  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
 
307
                                             &error))
 
308
    {
 
309
      g_simple_async_result_take_error (operation_result, error);
 
310
      g_simple_async_result_complete_in_idle (operation_result);
 
311
      g_object_unref (operation_result);
 
312
      return;
 
313
    }
 
314
 
 
315
  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
 
316
  password = g_object_get_data (G_OBJECT (operation_result), "password");
 
317
  identifier = g_simple_async_result_get_source_tag (operation_result);
 
318
 
 
319
  g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
 
320
 
 
321
  if (password != NULL)
 
322
    {
 
323
      GcrSecretExchange *secret_exchange;
 
324
      char *secret;
 
325
 
 
326
      secret_exchange = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
327
 
 
328
      secret = gcr_secret_exchange_send (secret_exchange, password, -1);
 
329
      g_variant_builder_add (&details, "{ss}", "initial-password", secret);
 
330
      g_free (secret);
 
331
    }
 
332
 
 
333
  goa_identity_service_manager_call_sign_in (self->identity_manager,
 
334
                                             identifier,
 
335
                                             g_variant_builder_end (&details),
 
336
                                             cancellable,
 
337
                                             (GAsyncReadyCallback)
 
338
                                             on_identity_signed_in,
 
339
                                             operation_result);
 
340
}
 
341
 
 
342
static void
 
343
on_secret_keys_exchanged (GoaIdentityServiceManager *manager,
 
344
                          GAsyncResult              *result,
 
345
                          GSimpleAsyncResult        *operation_result)
 
346
{
 
347
  GcrSecretExchange *secret_exchange;
 
348
  char              *return_key;
 
349
  GError            *error;
 
350
 
 
351
  secret_exchange = g_simple_async_result_get_source_tag (operation_result);
 
352
 
 
353
  error = NULL;
 
354
  if (!goa_identity_service_manager_call_exchange_secret_keys_finish (manager,
 
355
                                                                      &return_key,
 
356
                                                                      result,
 
357
                                                                      &error))
 
358
    {
 
359
      g_object_unref (secret_exchange);
 
360
 
 
361
      g_simple_async_result_take_error (operation_result, error);
 
362
      g_simple_async_result_complete_in_idle (operation_result);
 
363
      g_object_unref (operation_result);
 
364
      return;
 
365
    }
 
366
 
 
367
  if (!gcr_secret_exchange_receive (secret_exchange, return_key))
 
368
    {
 
369
      g_object_unref (secret_exchange);
 
370
 
 
371
      g_simple_async_result_set_error (operation_result,
 
372
                                       GCR_ERROR,
 
373
                                       GCR_ERROR_UNRECOGNIZED,
 
374
                                       _("Identity service returned invalid key"));
 
375
      g_simple_async_result_complete_in_idle (operation_result);
 
376
      g_object_unref (operation_result);
 
377
      return;
 
378
    }
 
379
 
 
380
  g_simple_async_result_set_op_res_gpointer (operation_result,
 
381
                                             secret_exchange,
 
382
                                             (GDestroyNotify)
 
383
                                             g_object_unref);
 
384
  g_simple_async_result_complete_in_idle (operation_result);
 
385
  g_object_unref (operation_result);
 
386
}
 
387
 
 
388
static void
 
389
exchange_secret_keys (GoaKerberosProvider  *self,
 
390
                      const char           *password,
 
391
                      GCancellable         *cancellable,
 
392
                      GAsyncReadyCallback   callback,
 
393
                      gpointer              user_data)
 
394
{
 
395
 
 
396
  GSimpleAsyncResult *operation_result;
 
397
  GcrSecretExchange  *secret_exchange;
 
398
  char               *secret_key;
 
399
 
 
400
  secret_exchange = gcr_secret_exchange_new (NULL);
 
401
 
 
402
  operation_result = g_simple_async_result_new (G_OBJECT (self),
 
403
                                                callback,
 
404
                                                user_data,
 
405
                                                secret_exchange);
 
406
 
 
407
  if (password == NULL)
 
408
    {
 
409
      g_simple_async_result_complete_in_idle (operation_result);
 
410
      g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
 
411
                                                 NULL,
 
412
                                                 NULL);
 
413
      return;
 
414
    }
 
415
 
 
416
  secret_key = gcr_secret_exchange_begin (secret_exchange);
 
417
 
 
418
  goa_identity_service_manager_call_exchange_secret_keys (self->identity_manager,
 
419
                                                          secret_key,
 
420
                                                          cancellable,
 
421
                                                          (GAsyncReadyCallback)
 
422
                                                          on_secret_keys_exchanged,
 
423
                                                          operation_result);
 
424
  g_free (secret_key);
 
425
}
 
426
 
 
427
static void
 
428
on_identity_manager_ensured_for_sign_in (GoaKerberosProvider *self,
 
429
                                         GAsyncResult        *result,
 
430
                                         GSimpleAsyncResult  *operation_result)
 
431
{
 
432
  GoaIdentityServiceManager *manager;
 
433
  const char                *password;
 
434
  GCancellable              *cancellable;
 
435
  GError                    *error;
 
436
 
 
437
  error = NULL;
 
438
 
 
439
  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
 
440
                                             &error))
 
441
    {
 
442
      g_simple_async_result_take_error (operation_result, error);
 
443
      g_simple_async_result_complete_in_idle (operation_result);
 
444
      g_object_unref (operation_result);
 
445
      return;
 
446
    }
 
447
 
 
448
  manager = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
449
 
 
450
  if (self->identity_manager == NULL)
 
451
    self->identity_manager = g_object_ref (manager);
 
452
 
 
453
  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
 
454
  password = g_object_get_data (G_OBJECT (operation_result), "password");
 
455
 
 
456
  exchange_secret_keys (self,
 
457
                        password,
 
458
                        cancellable,
 
459
                        (GAsyncReadyCallback)
 
460
                        on_secret_keys_exchanged_for_sign_in,
 
461
                        operation_result);
 
462
}
 
463
 
 
464
static void
 
465
sign_in_identity (GoaKerberosProvider  *self,
 
466
                  const char           *identifier,
 
467
                  const char           *password,
 
468
                  GCancellable         *cancellable,
 
469
                  GAsyncReadyCallback   callback,
 
470
                  gpointer              user_data)
 
471
{
 
472
  GSimpleAsyncResult *operation_result;
 
473
 
 
474
  operation_result = g_simple_async_result_new (G_OBJECT (self),
 
475
                                                callback,
 
476
                                                user_data,
 
477
                                                (gpointer)
 
478
                                                identifier);
 
479
 
 
480
  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
 
481
 
 
482
  g_object_set_data (G_OBJECT (operation_result),
 
483
                     "cancellable",
 
484
                     cancellable);
 
485
  g_object_set_data (G_OBJECT (operation_result),
 
486
                     "password",
 
487
                     (gpointer)
 
488
                     password);
 
489
 
 
490
  ensure_identity_manager (self,
 
491
                           cancellable,
 
492
                           (GAsyncReadyCallback)
 
493
                           on_identity_manager_ensured_for_sign_in,
 
494
                           operation_result);
 
495
}
 
496
 
 
497
static void
 
498
on_object_manager_ensured_for_look_up (GoaKerberosProvider *self,
 
499
                                       GAsyncResult        *result,
 
500
                                       GSimpleAsyncResult  *operation_result)
 
501
{
 
502
  GDBusObjectManager *manager;
 
503
  const char         *identifier;
 
504
  GList              *objects, *node;
 
505
  GError             *error;
 
506
 
 
507
  error = NULL;
 
508
 
 
509
  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
 
510
                                             &error))
 
511
    {
 
512
      g_simple_async_result_take_error (operation_result, error);
 
513
      g_simple_async_result_complete_in_idle (operation_result);
 
514
      g_object_unref (operation_result);
 
515
      return;
 
516
    }
 
517
 
 
518
  manager = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
519
 
 
520
  if (self->object_manager == NULL)
 
521
    self->object_manager = g_object_ref (manager);
 
522
 
 
523
  identifier = g_simple_async_result_get_source_tag (operation_result);
 
524
 
 
525
  g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
 
526
                                             NULL,
 
527
                                             NULL);
 
528
  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->object_manager));
 
529
 
 
530
  for (node = objects; node != NULL; node = node->next)
 
531
    {
 
532
      GoaIdentityServiceIdentity *candidate_identity;
 
533
      const char                 *candidate_identifier;
 
534
      GDBusObject                *object;
 
535
 
 
536
      object = node->data;
 
537
 
 
538
      candidate_identity = GOA_IDENTITY_SERVICE_IDENTITY (g_dbus_object_get_interface (object, "org.gnome.Identity"));
 
539
 
 
540
      if (candidate_identity == NULL)
 
541
        continue;
 
542
 
 
543
      candidate_identifier = goa_identity_service_identity_get_identifier (candidate_identity);
 
544
 
 
545
      if (g_strcmp0 (candidate_identifier, identifier) == 0)
 
546
        {
 
547
          g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
 
548
                                                     candidate_identity,
 
549
                                                     (GDestroyNotify)
 
550
                                                     g_object_unref);
 
551
          break;
 
552
        }
 
553
 
 
554
      g_object_unref (candidate_identity);
 
555
    }
 
556
 
 
557
  g_list_free_full (objects, (GDestroyNotify) g_object_unref);
 
558
  g_simple_async_result_complete_in_idle (G_SIMPLE_ASYNC_RESULT (operation_result));
 
559
  g_object_unref (operation_result);
 
560
}
 
561
 
 
562
static void
 
563
look_up_identity (GoaKerberosProvider  *self,
 
564
                  const char           *identifier,
 
565
                  GCancellable         *cancellable,
 
566
                  GAsyncReadyCallback   callback,
 
567
                  gpointer              user_data)
 
568
{
 
569
  GSimpleAsyncResult *operation_result;
 
570
 
 
571
  operation_result = g_simple_async_result_new (G_OBJECT (self),
 
572
                                                callback,
 
573
                                                user_data,
 
574
                                                (gpointer)
 
575
                                                identifier);
 
576
 
 
577
  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
 
578
 
 
579
  g_object_set_data (G_OBJECT (operation_result),
 
580
                     "cancellable",
 
581
                     cancellable);
 
582
  ensure_object_manager (self,
 
583
                         cancellable,
 
584
                         (GAsyncReadyCallback)
 
585
                         on_object_manager_ensured_for_look_up,
 
586
                         operation_result);
 
587
}
 
588
 
 
589
static void
 
590
on_account_signed_in (GoaProvider   *provider,
 
591
                      GAsyncResult  *result,
 
592
                      SignInRequest *request)
 
593
{
 
594
  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
 
595
                                             &request->error))
 
596
    {
 
597
      g_main_loop_quit (request->loop);
 
598
      return;
 
599
    }
 
600
 
 
601
  g_main_loop_quit (request->loop);
 
602
}
 
603
 
 
604
static gboolean
 
605
get_ticket_sync (GoaKerberosProvider *self,
 
606
                 GoaObject           *object,
 
607
                 gboolean             is_interactive,
 
608
                 GCancellable        *cancellable,
 
609
                 GError             **error)
 
610
{
 
611
  GVariant            *credentials;
 
612
  GError              *lookup_error;
 
613
  GoaAccount          *account;
 
614
  const char          *identifier;
 
615
  const char          *password;
 
616
  gboolean             has_password;
 
617
  SignInRequest        request;
 
618
  gboolean             ret;
 
619
 
 
620
  ret = FALSE;
 
621
 
 
622
  account = goa_object_peek_account (object);
 
623
  identifier = goa_account_get_identity (account);
 
624
  password = NULL;
 
625
 
 
626
  lookup_error = NULL;
 
627
  credentials = goa_utils_lookup_credentials_sync (GOA_PROVIDER (self),
 
628
                                                   object,
 
629
                                                   cancellable,
 
630
                                                   &lookup_error);
 
631
 
 
632
  if (credentials == NULL && !is_interactive)
 
633
    {
 
634
      if (lookup_error != NULL)
 
635
          g_propagate_error (error, lookup_error);
 
636
      else
 
637
          g_set_error (error,
 
638
                       GOA_ERROR,
 
639
                       GOA_ERROR_NOT_AUTHORIZED,
 
640
                       _("Could not find saved credentials for principal `%s' in keyring"), identifier);
 
641
      goto out;
 
642
    }
 
643
 
 
644
  has_password = g_variant_lookup (credentials, "password", "&s", &password);
 
645
  if (!has_password && !is_interactive)
 
646
    {
 
647
      g_set_error (error,
 
648
                   GOA_ERROR,
 
649
                   GOA_ERROR_NOT_AUTHORIZED,
 
650
                   _("Did not find password for principal `%s' in credentials"),
 
651
                   identifier);
 
652
      goto out;
 
653
    }
 
654
 
 
655
  memset (&request, 0, sizeof (SignInRequest));
 
656
  request.loop = g_main_loop_new (NULL, FALSE);
 
657
  request.error = NULL;
 
658
 
 
659
  sign_in_identity (self,
 
660
                    identifier,
 
661
                    password,
 
662
                    cancellable,
 
663
                    (GAsyncReadyCallback)
 
664
                    on_account_signed_in,
 
665
                    &request);
 
666
 
 
667
  g_main_loop_run (request.loop);
 
668
  g_main_loop_unref (request.loop);
 
669
 
 
670
  if (request.error != NULL)
 
671
    {
 
672
      g_propagate_error (error, request.error);
 
673
      goto out;
 
674
    }
 
675
 
 
676
  ret = TRUE;
 
677
out:
 
678
  if (credentials != NULL)
 
679
    g_variant_unref (credentials);
 
680
 
 
681
  return ret;
 
682
}
 
683
 
 
684
static void
 
685
notify_is_temporary_cb (GObject *object, GParamSpec *pspec, gpointer user_data)
 
686
{
 
687
  GoaAccount *account;
 
688
  gboolean is_temporary;
 
689
 
 
690
  /* Toggle IsTemporary */
 
691
  goa_util_account_notify_property_cb (object, pspec, "IsTemporary");
 
692
 
 
693
  account = GOA_ACCOUNT (object);
 
694
  g_object_get (account, "is-temporary", &is_temporary, NULL);
 
695
 
 
696
  /* Set/unset SessionId */
 
697
  if (is_temporary)
 
698
    {
 
699
      GDBusConnection *connection;
 
700
      const gchar *guid;
 
701
 
 
702
      connection = G_DBUS_CONNECTION (user_data);
 
703
      guid = g_dbus_connection_get_guid (connection);
 
704
      goa_utils_keyfile_set_string (account, "SessionId", guid);
 
705
    }
 
706
  else
 
707
    goa_utils_keyfile_remove_key (account, "SessionId");
 
708
}
 
709
 
 
710
static gboolean
 
711
on_handle_get_ticket (GoaTicketing          *interface,
 
712
                      GDBusMethodInvocation *invocation)
 
713
{
 
714
  GoaObject *object;
 
715
  GoaAccount *account;
 
716
  GoaProvider *provider;
 
717
  GError *error;
 
718
  gboolean got_ticket;
 
719
 
 
720
  object = GOA_OBJECT (g_dbus_interface_get_object (G_DBUS_INTERFACE (interface)));
 
721
  account = goa_object_peek_account (object);
 
722
 
 
723
  provider = goa_provider_get_for_provider_type (goa_account_get_provider_type (account));
 
724
  error = NULL;
 
725
  got_ticket = get_ticket_sync (GOA_KERBEROS_PROVIDER (provider),
 
726
                                object,
 
727
                                TRUE /* Allow interaction */,
 
728
                                NULL,
 
729
                                &error);
 
730
 
 
731
  if (!got_ticket)
 
732
    g_dbus_method_invocation_take_error (invocation, error);
 
733
  else
 
734
    goa_ticketing_complete_get_ticket (interface, invocation);
 
735
 
 
736
  g_object_unref (provider);
 
737
  return TRUE;
 
738
}
 
739
 
 
740
static gboolean
 
741
build_object (GoaProvider         *provider,
 
742
              GoaObjectSkeleton   *object,
 
743
              GKeyFile            *key_file,
 
744
              const gchar         *group,
 
745
              GDBusConnection     *connection,
 
746
              gboolean             just_added,
 
747
              GError             **error)
 
748
{
 
749
  GoaAccount   *account;
 
750
  GoaTicketing *ticketing;
 
751
  gboolean      ticketing_enabled;
 
752
  gboolean      ret;
 
753
 
 
754
  ticketing = NULL;
 
755
  ret = FALSE;
 
756
 
 
757
  if (!GOA_PROVIDER_CLASS (goa_kerberos_provider_parent_class)->build_object (provider,
 
758
                                                                              object,
 
759
                                                                              key_file,
 
760
                                                                              group,
 
761
                                                                              connection,
 
762
                                                                              just_added,
 
763
                                                                              error))
 
764
    goto out;
 
765
 
 
766
  account = goa_object_get_account (GOA_OBJECT (object));
 
767
 
 
768
  ticketing = goa_object_get_ticketing (GOA_OBJECT (object));
 
769
  ticketing_enabled = g_key_file_get_boolean (key_file, group, "TicketingEnabled", NULL);
 
770
 
 
771
  if (ticketing_enabled)
 
772
    {
 
773
      if (ticketing == NULL)
 
774
        {
 
775
          ticketing = goa_ticketing_skeleton_new ();
 
776
 
 
777
          g_signal_connect (ticketing,
 
778
                            "handle-get-ticket",
 
779
                            G_CALLBACK (on_handle_get_ticket),
 
780
                            NULL);
 
781
 
 
782
          goa_object_skeleton_set_ticketing (object, ticketing);
 
783
 
 
784
        }
 
785
    }
 
786
  else if (ticketing != NULL)
 
787
    {
 
788
      goa_object_skeleton_set_ticketing (object, NULL);
 
789
    }
 
790
 
 
791
  if (just_added)
 
792
    {
 
793
      goa_account_set_ticketing_disabled (account, !ticketing_enabled);
 
794
 
 
795
      g_signal_connect (account,
 
796
                        "notify::is-temporary",
 
797
                        G_CALLBACK (notify_is_temporary_cb),
 
798
                        connection);
 
799
 
 
800
      g_signal_connect (account,
 
801
                        "notify::ticketing-disabled",
 
802
                        G_CALLBACK (goa_util_account_notify_property_cb),
 
803
                        "TicketingEnabled");
 
804
    }
 
805
 
 
806
  ret = TRUE;
 
807
 
 
808
 out:
 
809
  g_clear_object (&ticketing);
 
810
 
 
811
  return ret;
 
812
}
 
813
 
 
814
static void
 
815
add_entry (GtkWidget     *grid1,
 
816
           GtkWidget     *grid2,
 
817
           const gchar   *text,
 
818
           GtkWidget    **out_entry)
 
819
{
 
820
  GtkStyleContext *context;
 
821
  GtkWidget *label;
 
822
  GtkWidget *entry;
 
823
 
 
824
  label = gtk_label_new_with_mnemonic (text);
 
825
  context = gtk_widget_get_style_context (label);
 
826
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
 
827
  gtk_widget_set_vexpand (label, TRUE);
 
828
  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
 
829
  gtk_container_add (GTK_CONTAINER (grid1), label);
 
830
 
 
831
  entry = gtk_entry_new ();
 
832
  gtk_widget_set_hexpand (entry, TRUE);
 
833
  gtk_widget_set_vexpand (entry, TRUE);
 
834
  gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
 
835
  gtk_entry_set_max_length (GTK_ENTRY (entry), 132);
 
836
  gtk_container_add (GTK_CONTAINER (grid2), entry);
 
837
 
 
838
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
 
839
  if (out_entry != NULL)
 
840
    *out_entry = entry;
 
841
}
 
842
 
 
843
static void
 
844
add_combo_box (GtkWidget     *grid1,
 
845
               GtkWidget     *grid2,
 
846
               const gchar   *text,
 
847
               const gchar   *placeholder,
 
848
               GtkListStore  *model,
 
849
               GtkWidget    **out_combo_box,
 
850
               GtkWidget    **out_entry)
 
851
{
 
852
  GtkStyleContext *context;
 
853
  GtkWidget *label;
 
854
  GtkWidget *combo_box;
 
855
  GtkWidget *entry;
 
856
 
 
857
  label = gtk_label_new_with_mnemonic (text);
 
858
  context = gtk_widget_get_style_context (label);
 
859
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_DIM_LABEL);
 
860
  gtk_widget_set_vexpand (label, TRUE);
 
861
  gtk_misc_set_alignment (GTK_MISC (label), 1.0, 0.5);
 
862
  gtk_container_add (GTK_CONTAINER (grid1), label);
 
863
 
 
864
  combo_box = gtk_combo_box_new_with_model_and_entry (GTK_TREE_MODEL (model));
 
865
  gtk_widget_set_hexpand (combo_box, TRUE);
 
866
  gtk_widget_set_vexpand (combo_box, TRUE);
 
867
  gtk_widget_show (combo_box);
 
868
 
 
869
  entry = gtk_bin_get_child (GTK_BIN (combo_box));
 
870
  gtk_entry_set_max_length (GTK_ENTRY (entry), 132);
 
871
  gtk_entry_set_placeholder_text (GTK_ENTRY (entry), placeholder);
 
872
 
 
873
  gtk_container_add (GTK_CONTAINER (grid2), combo_box);
 
874
 
 
875
  gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
 
876
  if (out_combo_box != NULL)
 
877
    *out_combo_box = combo_box;
 
878
 
 
879
  if (out_entry != NULL)
 
880
    *out_entry = entry;
 
881
}
 
882
 
 
883
static void
 
884
on_realm_added (GDBusObjectManager       *manager,
 
885
                GoaIdentityServiceObject *object,
 
886
                GDBusInterface           *interface,
 
887
                SignInRequest            *request)
 
888
{
 
889
  GoaIdentityServiceRealm *realm;
 
890
  GDBusInterfaceInfo      *info;
 
891
  GtkTreeIter              iter;
 
892
 
 
893
  info = g_dbus_interface_get_info (interface);
 
894
 
 
895
  if (g_strcmp0 (info->name, "org.gnome.Identity.Realm") != 0)
 
896
    return;
 
897
 
 
898
  realm = goa_identity_service_object_peek_realm (object);
 
899
 
 
900
  if (realm == NULL)
 
901
    return;
 
902
 
 
903
  gtk_list_store_append (request->realm_store, &iter);
 
904
  gtk_list_store_set (request->realm_store,
 
905
                      &iter,
 
906
                      0, goa_identity_service_realm_get_domain (realm),
 
907
                      1, realm,
 
908
                     -1);
 
909
 
 
910
  if (!request->realm_chosen && goa_identity_service_realm_get_is_enrolled (realm))
 
911
    gtk_combo_box_set_active_iter (GTK_COMBO_BOX (request->realm_combo_box), &iter);
 
912
}
 
913
 
 
914
static void
 
915
on_object_manager_ensured_for_getting_realms (GoaKerberosProvider *self,
 
916
                                              GAsyncResult        *result,
 
917
                                              SignInRequest       *request)
 
918
{
 
919
  GDBusObjectManager *manager;
 
920
  GList              *objects, *node;
 
921
  GError             *error;
 
922
 
 
923
  error = NULL;
 
924
 
 
925
  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
 
926
                                             &error))
 
927
    return;
 
928
 
 
929
  manager = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
930
 
 
931
  if (self->object_manager == NULL)
 
932
    self->object_manager = g_object_ref (manager);
 
933
 
 
934
  objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (self->object_manager));
 
935
 
 
936
  for (node = objects; node != NULL; node = node->next)
 
937
    {
 
938
      GoaIdentityServiceRealm *realm;
 
939
      GDBusObject             *object;
 
940
      GtkTreeIter              iter;
 
941
 
 
942
      object = node->data;
 
943
 
 
944
      realm = GOA_IDENTITY_SERVICE_REALM (g_dbus_object_get_interface (object, "org.gnome.Identity.Realm"));
 
945
 
 
946
      if (realm == NULL)
 
947
        continue;
 
948
 
 
949
      gtk_list_store_append (request->realm_store, &iter);
 
950
      gtk_list_store_set (request->realm_store,
 
951
                          &iter,
 
952
                          0, goa_identity_service_realm_get_domain (realm),
 
953
                          1, realm,
 
954
                          -1);
 
955
 
 
956
      if (!request->realm_chosen && goa_identity_service_realm_get_is_enrolled (realm))
 
957
        gtk_combo_box_set_active_iter (GTK_COMBO_BOX (request->realm_combo_box), &iter);
 
958
    }
 
959
 
 
960
  request->interface_added_id = g_signal_connect (self->object_manager,
 
961
                                                  "interface-added",
 
962
                                                  G_CALLBACK (on_realm_added),
 
963
                                                  request);
 
964
 
 
965
  g_list_free_full (objects, (GDestroyNotify) g_object_unref);
 
966
}
 
967
 
 
968
static void
 
969
create_account_details_ui (GoaKerberosProvider *self,
 
970
                           GtkWidget           *vbox,
 
971
                           gboolean             new_account,
 
972
                           SignInRequest       *request)
 
973
{
 
974
  GtkWidget *header_grid;
 
975
  GtkWidget *grid1;
 
976
  GtkWidget *grid2;
 
977
  GtkWidget *hbox;
 
978
  GtkWidget *label;
 
979
  gchar *markup;
 
980
  gint width;
 
981
 
 
982
  header_grid = gtk_grid_new ();
 
983
  gtk_orientable_set_orientation (GTK_ORIENTABLE (header_grid), GTK_ORIENTATION_HORIZONTAL);
 
984
  gtk_box_pack_start (GTK_BOX (vbox), header_grid, FALSE, FALSE, 0);
 
985
 
 
986
  label = gtk_label_new (NULL);
 
987
  gtk_widget_set_hexpand (label, TRUE);
 
988
  markup = g_strconcat ("<b>",
 
989
                        (new_account) ? _("New Enterprise Login (Kerberos)") : _("Enterpise Login (Kerberos)"),
 
990
                        "</b>",
 
991
                        NULL);
 
992
  gtk_label_set_markup (GTK_LABEL (label), markup);
 
993
  g_free (markup);
 
994
  gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
 
995
  gtk_misc_set_padding (GTK_MISC (label), 0.0, 12);
 
996
  gtk_container_add (GTK_CONTAINER (header_grid), label);
 
997
 
 
998
  request->spinner = gtk_spinner_new ();
 
999
  gtk_widget_set_no_show_all (request->spinner, TRUE);
 
1000
  gtk_container_add (GTK_CONTAINER (header_grid), request->spinner);
 
1001
 
 
1002
  request->cluebar = gtk_info_bar_new ();
 
1003
  gtk_info_bar_set_message_type (GTK_INFO_BAR (request->cluebar), GTK_MESSAGE_ERROR);
 
1004
  gtk_widget_set_no_show_all (request->cluebar, TRUE);
 
1005
  gtk_box_pack_start (GTK_BOX (vbox), request->cluebar, FALSE, FALSE, 0);
 
1006
 
 
1007
  request->cluebar_label = gtk_label_new ("");
 
1008
  gtk_label_set_line_wrap (GTK_LABEL (request->cluebar_label), TRUE);
 
1009
  gtk_container_add (GTK_CONTAINER (gtk_info_bar_get_content_area (GTK_INFO_BAR (request->cluebar))),
 
1010
                     request->cluebar_label);
 
1011
 
 
1012
  grid1 = gtk_grid_new ();
 
1013
  gtk_orientable_set_orientation (GTK_ORIENTABLE (grid1), GTK_ORIENTATION_VERTICAL);
 
1014
  gtk_grid_set_row_spacing (GTK_GRID (grid1), 12);
 
1015
 
 
1016
  grid2 = gtk_grid_new ();
 
1017
  gtk_orientable_set_orientation (GTK_ORIENTABLE (grid2), GTK_ORIENTATION_VERTICAL);
 
1018
  gtk_grid_set_row_spacing (GTK_GRID (grid2), 12);
 
1019
 
 
1020
  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
 
1021
  gtk_box_set_homogeneous (GTK_BOX (hbox), FALSE);
 
1022
  gtk_box_pack_start (GTK_BOX (hbox), grid1, FALSE, FALSE, 0);
 
1023
  gtk_box_pack_start (GTK_BOX (hbox), grid2, TRUE, TRUE, 0);
 
1024
  gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
 
1025
 
 
1026
  request->realm_store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_OBJECT);
 
1027
  add_combo_box (grid1,
 
1028
                 grid2,
 
1029
                 _("_Domain"),
 
1030
                 _("Enterprise domain or realm name"),
 
1031
                 request->realm_store,
 
1032
                 &request->realm_combo_box,
 
1033
                 &request->realm_entry);
 
1034
  gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (request->realm_combo_box), 0);
 
1035
 
 
1036
  add_entry (grid1, grid2, _("User_name"), &request->username);
 
1037
 
 
1038
  ensure_object_manager (self,
 
1039
                         NULL,
 
1040
                         (GAsyncReadyCallback)
 
1041
                         on_object_manager_ensured_for_getting_realms,
 
1042
                         request);
 
1043
 
 
1044
  gtk_widget_grab_focus (request->realm_combo_box);
 
1045
 
 
1046
  gtk_dialog_add_button (request->dialog, GTK_STOCK_CONNECT, GTK_RESPONSE_OK);
 
1047
  gtk_dialog_set_default_response (request->dialog, GTK_RESPONSE_OK);
 
1048
  gtk_dialog_set_response_sensitive (request->dialog, GTK_RESPONSE_OK, TRUE);
 
1049
 
 
1050
  gtk_window_get_size (GTK_WINDOW (request->dialog), &width, NULL);
 
1051
  gtk_widget_set_size_request (GTK_WIDGET (request->dialog), width, -1);
 
1052
}
 
1053
 
 
1054
static void
 
1055
add_account_cb (GoaManager   *manager,
 
1056
                GAsyncResult *result,
 
1057
                gpointer      user_data)
 
1058
{
 
1059
  SignInRequest *request = user_data;
 
1060
  goa_manager_call_add_account_finish (manager,
 
1061
                                       &request->account_object_path,
 
1062
                                       result,
 
1063
                                       &request->error);
 
1064
  if (request->error != NULL)
 
1065
    translate_error (&request->error);
 
1066
  g_main_loop_quit (request->loop);
 
1067
}
 
1068
 
 
1069
static void
 
1070
remove_account_cb (GoaAccount   *account,
 
1071
                   GAsyncResult *result,
 
1072
                   GMainLoop    *loop)
 
1073
{
 
1074
  goa_account_call_remove_finish (account, result, NULL);
 
1075
  g_main_loop_quit (loop);
 
1076
}
 
1077
 
 
1078
static gboolean
 
1079
refresh_account (GoaProvider    *provider,
 
1080
                 GoaClient      *client,
 
1081
                 GoaObject      *object,
 
1082
                 GtkWindow      *parent,
 
1083
                 GError        **error)
 
1084
{
 
1085
  GoaKerberosProvider *self = GOA_KERBEROS_PROVIDER (provider);
 
1086
  gboolean             got_ticket;
 
1087
  GError              *ticket_error = NULL;
 
1088
 
 
1089
  g_return_val_if_fail (GOA_IS_KERBEROS_PROVIDER (provider), FALSE);
 
1090
  g_return_val_if_fail (GOA_IS_CLIENT (client), FALSE);
 
1091
  g_return_val_if_fail (GOA_IS_OBJECT (object), FALSE);
 
1092
  g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), FALSE);
 
1093
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
1094
 
 
1095
  got_ticket = get_ticket_sync (self,
 
1096
                                object,
 
1097
                                TRUE /* Allow interaction */,
 
1098
                                NULL,
 
1099
                                &ticket_error);
 
1100
 
 
1101
  if (ticket_error != NULL)
 
1102
    {
 
1103
      translate_error (&ticket_error);
 
1104
      g_propagate_error (error, ticket_error);
 
1105
    }
 
1106
 
 
1107
  return got_ticket;
 
1108
}
 
1109
 
 
1110
static void
 
1111
on_initial_sign_in_done (GoaKerberosProvider *self,
 
1112
                         GAsyncResult        *result,
 
1113
                         GSimpleAsyncResult  *operation_result)
 
1114
{
 
1115
  GError    *error;
 
1116
  gboolean   remember_password;
 
1117
  GoaObject *object;
 
1118
 
 
1119
  object = g_simple_async_result_get_source_tag (operation_result);
 
1120
 
 
1121
  remember_password = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (operation_result),
 
1122
                                                          "remember-password"));
 
1123
 
 
1124
  error = NULL;
 
1125
  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error))
 
1126
    {
 
1127
      g_simple_async_result_take_error (operation_result, error);
 
1128
    }
 
1129
  else if (remember_password)
 
1130
    {
 
1131
      GVariantBuilder  builder;
 
1132
      const char      *object_path;
 
1133
 
 
1134
      object_path = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
1135
 
 
1136
      if (object_path != NULL && object != NULL)
 
1137
        {
 
1138
          GcrSecretExchange *secret_exchange;
 
1139
          const char        *password;
 
1140
 
 
1141
          secret_exchange = g_object_get_data (G_OBJECT (operation_result), "secret-exchange");
 
1142
          password = gcr_secret_exchange_get_secret (secret_exchange, NULL);
 
1143
 
 
1144
          /* FIXME: we go to great lengths to keep the password in non-pageable memory,
 
1145
           * and then just duplicate it into a gvariant here
 
1146
           */
 
1147
          g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
 
1148
          g_variant_builder_add (&builder,
 
1149
                                 "{sv}",
 
1150
                                 "password",
 
1151
                                 g_variant_new_string (password));
 
1152
 
 
1153
          error = NULL;
 
1154
          goa_utils_store_credentials_for_object_sync (GOA_PROVIDER (self),
 
1155
                                                       object,
 
1156
                                                       g_variant_builder_end (&builder),
 
1157
                                                       NULL,
 
1158
                                                       NULL);
 
1159
        }
 
1160
    }
 
1161
 
 
1162
  g_simple_async_result_complete_in_idle (operation_result);
 
1163
  g_object_unref (operation_result);
 
1164
}
 
1165
 
 
1166
static void
 
1167
on_system_prompt_answered_for_initial_sign_in (GcrPrompt          *prompt,
 
1168
                                               GAsyncResult       *result,
 
1169
                                               GSimpleAsyncResult *operation_result)
 
1170
{
 
1171
  GoaKerberosProvider *self;
 
1172
  GCancellable        *cancellable;
 
1173
  GError              *error;
 
1174
  const char          *principal;
 
1175
  const char          *password;
 
1176
  GcrSecretExchange   *secret_exchange;
 
1177
 
 
1178
  self = GOA_KERBEROS_PROVIDER (g_async_result_get_source_object (G_ASYNC_RESULT (operation_result)));
 
1179
  principal = g_object_get_data (G_OBJECT (operation_result), "principal");
 
1180
  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
 
1181
 
 
1182
  error = NULL;
 
1183
  password = gcr_prompt_password_finish (prompt, result, &error);
 
1184
 
 
1185
  if (password == NULL)
 
1186
    {
 
1187
      gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, NULL);
 
1188
 
 
1189
      if (error != NULL)
 
1190
        g_simple_async_result_take_error (operation_result, error);
 
1191
      else
 
1192
        g_cancellable_cancel (cancellable);
 
1193
 
 
1194
      g_simple_async_result_complete_in_idle (operation_result);
 
1195
      g_object_unref (operation_result);
 
1196
      return;
 
1197
    }
 
1198
 
 
1199
  secret_exchange = gcr_system_prompt_get_secret_exchange (GCR_SYSTEM_PROMPT (prompt));
 
1200
  g_object_set_data_full (G_OBJECT (operation_result),
 
1201
                          "secret-exchange",
 
1202
                          g_object_ref (secret_exchange),
 
1203
                          (GDestroyNotify)
 
1204
                          g_object_unref);
 
1205
 
 
1206
  g_object_set_data (G_OBJECT (operation_result),
 
1207
                     "remember-password",
 
1208
                     GINT_TO_POINTER (gcr_prompt_get_choice_chosen (prompt)));
 
1209
 
 
1210
  gcr_system_prompt_close (GCR_SYSTEM_PROMPT (prompt), NULL, NULL);
 
1211
 
 
1212
  sign_in_identity (self,
 
1213
                    principal,
 
1214
                    password,
 
1215
                    cancellable,
 
1216
                    (GAsyncReadyCallback)
 
1217
                    on_initial_sign_in_done,
 
1218
                    operation_result);
 
1219
}
 
1220
 
 
1221
static void
 
1222
on_system_prompt_open_for_initial_sign_in (GcrSystemPrompt     *system_prompt,
 
1223
                                           GAsyncResult        *result,
 
1224
                                           GSimpleAsyncResult  *operation_result)
 
1225
{
 
1226
  GCancellable *cancellable;
 
1227
  GcrPrompt    *prompt;
 
1228
  GError       *error;
 
1229
 
 
1230
  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
 
1231
  error = NULL;
 
1232
  prompt = gcr_system_prompt_open_finish (result, &error);
 
1233
 
 
1234
  if (prompt == NULL)
 
1235
    {
 
1236
      g_simple_async_result_take_error (operation_result, error);
 
1237
 
 
1238
      g_simple_async_result_complete_in_idle (operation_result);
 
1239
      g_object_unref (operation_result);
 
1240
 
 
1241
      return;
 
1242
    }
 
1243
 
 
1244
  gcr_prompt_set_title (prompt, _("Log In to Realm"));
 
1245
  gcr_prompt_set_description (prompt, _("Please enter your password below."));
 
1246
  gcr_prompt_set_choice_label (prompt, _("Remember this password"));
 
1247
 
 
1248
  gcr_prompt_password_async (prompt,
 
1249
                             cancellable,
 
1250
                             (GAsyncReadyCallback)
 
1251
                             on_system_prompt_answered_for_initial_sign_in,
 
1252
                             operation_result);
 
1253
}
 
1254
 
 
1255
static void
 
1256
perform_initial_sign_in (GoaKerberosProvider *self,
 
1257
                         GoaObject           *object,
 
1258
                         const char          *principal,
 
1259
                         SignInRequest       *request)
 
1260
{
 
1261
 
 
1262
  GSimpleAsyncResult *operation_result;
 
1263
  GCancellable       *cancellable;
 
1264
 
 
1265
  cancellable = g_cancellable_new ();
 
1266
 
 
1267
  operation_result = g_simple_async_result_new (G_OBJECT (self),
 
1268
                                                (GAsyncReadyCallback)
 
1269
                                                on_account_signed_in ,
 
1270
                                                request,
 
1271
                                                object);
 
1272
  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
 
1273
 
 
1274
  g_object_set_data (G_OBJECT (operation_result),
 
1275
                     "cancellable",
 
1276
                     cancellable);
 
1277
  g_object_set_data (G_OBJECT (operation_result),
 
1278
                     "principal",
 
1279
                     (gpointer)
 
1280
                     principal);
 
1281
 
 
1282
  gcr_system_prompt_open_async (-1,
 
1283
                                cancellable,
 
1284
                                (GAsyncReadyCallback)
 
1285
                                on_system_prompt_open_for_initial_sign_in,
 
1286
                                operation_result);
 
1287
}
 
1288
 
 
1289
static char *
 
1290
get_realm (SignInRequest *request)
 
1291
{
 
1292
  char *realm;
 
1293
  GtkTreeIter iter;
 
1294
 
 
1295
  if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (request->realm_combo_box), &iter))
 
1296
    gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (request->realm_combo_box)),
 
1297
                        &iter,
 
1298
                        0, &realm,
 
1299
                        -1);
 
1300
  else
 
1301
    realm = g_strdup (gtk_entry_get_text (GTK_ENTRY (request->realm_entry)));
 
1302
 
 
1303
  return realm;
 
1304
}
 
1305
 
 
1306
static GoaObject *
 
1307
add_account (GoaProvider    *provider,
 
1308
             GoaClient      *client,
 
1309
             GtkDialog      *dialog,
 
1310
             GtkBox         *vbox,
 
1311
             GError        **error)
 
1312
{
 
1313
  GoaKerberosProvider *self = GOA_KERBEROS_PROVIDER (provider);
 
1314
  SignInRequest request;
 
1315
  GVariantBuilder credentials;
 
1316
  GVariantBuilder details;
 
1317
  GoaObject   *object;
 
1318
  GoaAccount  *account;
 
1319
  char        *realm;
 
1320
  const char  *username;
 
1321
  const char *provider_type;
 
1322
  gchar      *principal;
 
1323
  gchar      *principal_for_display;
 
1324
  gint        response;
 
1325
 
 
1326
  object = NULL;
 
1327
  principal = NULL;
 
1328
  principal_for_display = NULL;
 
1329
 
 
1330
  memset (&request, 0, sizeof (SignInRequest));
 
1331
  request.loop = g_main_loop_new (NULL, FALSE);
 
1332
  request.dialog = dialog;
 
1333
  request.error = NULL;
 
1334
 
 
1335
  create_account_details_ui (self, GTK_WIDGET (vbox), TRUE, &request);
 
1336
  gtk_widget_show_all (GTK_WIDGET (vbox));
 
1337
 
 
1338
start_over:
 
1339
  response = gtk_dialog_run (dialog);
 
1340
 
 
1341
  if (response != GTK_RESPONSE_OK)
 
1342
    {
 
1343
      g_set_error (&request.error,
 
1344
                   GOA_ERROR,
 
1345
                   GOA_ERROR_DIALOG_DISMISSED,
 
1346
                   _("Dialog was dismissed"));
 
1347
      goto out;
 
1348
    }
 
1349
 
 
1350
  realm = get_realm (&request);
 
1351
  username = gtk_entry_get_text (GTK_ENTRY (request.username));
 
1352
 
 
1353
  g_free (principal);
 
1354
  principal = g_strdup_printf ("%s@%s", username, realm);
 
1355
 
 
1356
  /* See if there's already an account of this type with the
 
1357
   * given identity
 
1358
   */
 
1359
  provider_type = goa_provider_get_provider_type (provider);
 
1360
 
 
1361
  if (!goa_utils_check_duplicate (client,
 
1362
                                  principal,
 
1363
                                  provider_type,
 
1364
                                  (GoaPeekInterfaceFunc) goa_object_peek_account,
 
1365
                                  &request.error))
 
1366
    goto out;
 
1367
 
 
1368
  /* If there isn't an account, then go ahead and create one
 
1369
   */
 
1370
  g_variant_builder_init (&credentials, G_VARIANT_TYPE_VARDICT);
 
1371
 
 
1372
  g_variant_builder_init (&details, G_VARIANT_TYPE ("a{ss}"));
 
1373
  g_variant_builder_add (&details, "{ss}", "Realm", realm);
 
1374
  g_variant_builder_add (&details, "{ss}", "IsTemporary", "true");
 
1375
  g_variant_builder_add (&details, "{ss}", "TicketingEnabled", "true");
 
1376
 
 
1377
  g_free (principal_for_display);
 
1378
  principal_for_display = g_strdup_printf ("%s@%s", username, realm);
 
1379
 
 
1380
  g_free (realm);
 
1381
 
 
1382
  goa_manager_call_add_account (goa_client_get_manager (client),
 
1383
                                goa_provider_get_provider_type (provider),
 
1384
                                principal,
 
1385
                                principal_for_display,
 
1386
                                g_variant_builder_end (&credentials),
 
1387
                                g_variant_builder_end (&details),
 
1388
                                NULL, /* GCancellable* */
 
1389
                                (GAsyncReadyCallback) add_account_cb,
 
1390
                                &request);
 
1391
  g_main_loop_run (request.loop);
 
1392
  if (request.error != NULL)
 
1393
    goto out;
 
1394
 
 
1395
  object = GOA_OBJECT (g_dbus_object_manager_get_object (goa_client_get_object_manager (client),
 
1396
                                                         request.account_object_path));
 
1397
  account = goa_object_peek_account (object);
 
1398
 
 
1399
  gtk_spinner_start (GTK_SPINNER (request.spinner));
 
1400
  gtk_widget_show (request.spinner);
 
1401
 
 
1402
  /* After the account is created, try to sign it in
 
1403
   */
 
1404
  perform_initial_sign_in (self, object, principal, &request);
 
1405
 
 
1406
  g_main_loop_run (request.loop);
 
1407
 
 
1408
  if (request.error != NULL)
 
1409
    {
 
1410
      GtkWidget *button;
 
1411
      gchar *markup;
 
1412
 
 
1413
      translate_error (&request.error);
 
1414
 
 
1415
      if (!g_error_matches (request.error,
 
1416
                            G_IO_ERROR,
 
1417
                            G_IO_ERROR_CANCELLED))
 
1418
        {
 
1419
          markup = g_strdup_printf ("<b>%s:</b>\n%s",
 
1420
                                    _("Error connecting to enterperise identity server"),
 
1421
                                    request.error->message);
 
1422
          gtk_label_set_markup (GTK_LABEL (request.cluebar_label), markup);
 
1423
          g_free (markup);
 
1424
 
 
1425
          button = gtk_dialog_get_widget_for_response (request.dialog, GTK_RESPONSE_OK);
 
1426
          gtk_button_set_label (GTK_BUTTON (button), _("_Try Again"));
 
1427
          gtk_widget_set_no_show_all (request.cluebar, FALSE);
 
1428
          gtk_widget_show_all (request.cluebar);
 
1429
        }
 
1430
      g_clear_error (&request.error);
 
1431
 
 
1432
      /* If it couldn't be signed in, then delete it and start over
 
1433
       */
 
1434
      goa_account_call_remove (account,
 
1435
                               NULL,
 
1436
                               (GAsyncReadyCallback)
 
1437
                               remove_account_cb,
 
1438
                               request.loop);
 
1439
      g_main_loop_run (request.loop);
 
1440
      g_clear_object (&object);
 
1441
      goto start_over;
 
1442
    }
 
1443
 
 
1444
  gtk_widget_hide (GTK_WIDGET (dialog));
 
1445
 
 
1446
 out:
 
1447
  /* We might have an object even when request.error is set.
 
1448
   * eg., if we failed to store the credentials in the keyring.
 
1449
   */
 
1450
  if (request.error != NULL)
 
1451
    {
 
1452
      translate_error (&request.error);
 
1453
      g_propagate_error (error, request.error);
 
1454
    }
 
1455
  else
 
1456
    g_assert (object != NULL);
 
1457
 
 
1458
  if (request.interface_added_id != 0)
 
1459
    g_signal_handler_disconnect (G_OBJECT (self->object_manager), request.interface_added_id);
 
1460
 
 
1461
  g_free (request.account_object_path);
 
1462
  g_free (principal);
 
1463
  g_free (principal_for_display);
 
1464
  if (request.loop != NULL)
 
1465
    g_main_loop_unref (request.loop);
 
1466
  return object;
 
1467
}
 
1468
 
 
1469
static void
 
1470
show_account (GoaProvider *provider,
 
1471
              GoaClient   *client,
 
1472
              GoaObject   *object,
 
1473
              GtkBox      *vbox,
 
1474
              GtkGrid     *left,
 
1475
              GtkGrid     *right)
 
1476
{
 
1477
  GOA_PROVIDER_CLASS (goa_kerberos_provider_parent_class)->show_account (provider,
 
1478
                                                                         client,
 
1479
                                                                         object,
 
1480
                                                                         vbox,
 
1481
                                                                         left,
 
1482
                                                                         right);
 
1483
  goa_util_add_row_switch_from_keyfile_with_blurb (left, right, object,
 
1484
                                                   _("Use for"),
 
1485
                                                   "ticketing-disabled",
 
1486
                                                   _("Network Resources"));
 
1487
}
 
1488
 
 
1489
static void
 
1490
on_identity_looked_up (GoaKerberosProvider *provider,
 
1491
                       GAsyncResult        *result,
 
1492
                       GSimpleAsyncResult  *operation_result)
 
1493
{
 
1494
 
 
1495
  GoaIdentityServiceIdentity *identity;
 
1496
  GError                     *error;
 
1497
 
 
1498
  error = NULL;
 
1499
  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error))
 
1500
    {
 
1501
      g_simple_async_result_take_error (operation_result, error);
 
1502
      g_simple_async_result_complete_in_idle (operation_result);
 
1503
      g_object_unref (operation_result);
 
1504
      return;
 
1505
    }
 
1506
 
 
1507
  identity = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
1508
  if (identity != NULL)
 
1509
    g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
 
1510
                                               g_object_ref (identity),
 
1511
                                               (GDestroyNotify)
 
1512
                                               g_object_unref);
 
1513
  else
 
1514
    g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
 
1515
                                               NULL,
 
1516
                                               NULL);
 
1517
 
 
1518
  g_simple_async_result_complete_in_idle (operation_result);
 
1519
  g_object_unref (operation_result);
 
1520
}
 
1521
 
 
1522
static void
 
1523
on_identity_looked_up_to_ensure_credentials (GoaKerberosProvider *self,
 
1524
                                             GAsyncResult        *result,
 
1525
                                             GSimpleAsyncResult  *operation_result)
 
1526
{
 
1527
 
 
1528
  GoaIdentityServiceIdentity *identity;
 
1529
  GError                     *error;
 
1530
  GoaObject                  *object;
 
1531
  GoaAccount                 *account;
 
1532
  const char                 *identifier;
 
1533
  GCancellable               *cancellable;
 
1534
 
 
1535
  error = NULL;
 
1536
  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), &error))
 
1537
    {
 
1538
      g_simple_async_result_take_error (operation_result, error);
 
1539
      g_simple_async_result_complete_in_idle (operation_result);
 
1540
      g_object_unref (operation_result);
 
1541
      return;
 
1542
    }
 
1543
 
 
1544
  identity = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result));
 
1545
 
 
1546
  if (identity != NULL && goa_identity_service_identity_get_is_signed_in (identity))
 
1547
    {
 
1548
      g_simple_async_result_set_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (operation_result),
 
1549
                                                 g_object_ref (identity),
 
1550
                                                 (GDestroyNotify)
 
1551
                                                 g_object_unref);
 
1552
      g_simple_async_result_complete_in_idle (operation_result);
 
1553
      g_object_unref (operation_result);
 
1554
      return;
 
1555
    }
 
1556
 
 
1557
  object = GOA_OBJECT (g_async_result_get_source_object (G_ASYNC_RESULT (operation_result)));
 
1558
  cancellable = g_object_get_data (G_OBJECT (operation_result), "cancellable");
 
1559
 
 
1560
  if (!get_ticket_sync (self,
 
1561
                        object,
 
1562
                        FALSE /* Don't allow interaction */,
 
1563
                        cancellable,
 
1564
                        &error))
 
1565
    {
 
1566
      g_simple_async_result_take_error (operation_result, error);
 
1567
      g_simple_async_result_complete_in_idle (operation_result);
 
1568
      g_object_unref (operation_result);
 
1569
      return;
 
1570
    }
 
1571
 
 
1572
  account = goa_object_peek_account (object);
 
1573
  identifier = goa_account_get_identity (account);
 
1574
 
 
1575
  look_up_identity (self,
 
1576
                    identifier,
 
1577
                    cancellable,
 
1578
                    (GAsyncReadyCallback)
 
1579
                    on_identity_looked_up,
 
1580
                    operation_result);
 
1581
 
 
1582
  g_simple_async_result_complete_in_idle (operation_result);
 
1583
  g_object_unref (operation_result);
 
1584
}
 
1585
 
 
1586
static void
 
1587
on_credentials_ensured (GoaObject    *object,
 
1588
                        GAsyncResult *result,
 
1589
                        GMainLoop    *loop)
 
1590
{
 
1591
  g_main_loop_quit (loop);
 
1592
}
 
1593
 
 
1594
static gboolean
 
1595
ensure_credentials_sync (GoaProvider    *provider,
 
1596
                         GoaObject      *object,
 
1597
                         gint           *out_expires_in,
 
1598
                         GCancellable   *cancellable,
 
1599
                         GError        **error)
 
1600
{
 
1601
  GoaIdentityServiceIdentity *identity;
 
1602
  GoaAccount                 *account;
 
1603
  const char                 *identifier;
 
1604
  GSimpleAsyncResult         *operation_result;
 
1605
  GMainLoop                  *loop;
 
1606
  GMainContext               *context;
 
1607
  gint64                      timestamp;
 
1608
  GDateTime                  *now, *expiration_time;
 
1609
  GTimeSpan                   time_span;
 
1610
  GError                     *lookup_error;
 
1611
 
 
1612
  account = goa_object_peek_account (object);
 
1613
  identifier = goa_account_get_identity (account);
 
1614
 
 
1615
  context = g_main_context_new ();
 
1616
  g_main_context_push_thread_default (context);
 
1617
  loop = g_main_loop_new (context, FALSE);
 
1618
  operation_result = g_simple_async_result_new (G_OBJECT (object),
 
1619
                                                (GAsyncReadyCallback)
 
1620
                                                on_credentials_ensured,
 
1621
                                                loop,
 
1622
                                                ensure_credentials_sync);
 
1623
  g_simple_async_result_set_check_cancellable (operation_result, cancellable);
 
1624
 
 
1625
  g_object_set_data (G_OBJECT (operation_result),
 
1626
                     "cancellable",
 
1627
                     cancellable);
 
1628
 
 
1629
  g_object_ref (operation_result);
 
1630
  look_up_identity (GOA_KERBEROS_PROVIDER (provider),
 
1631
                    identifier,
 
1632
                    cancellable,
 
1633
                    (GAsyncReadyCallback)
 
1634
                    on_identity_looked_up_to_ensure_credentials,
 
1635
                    operation_result);
 
1636
 
 
1637
  g_main_loop_run (loop);
 
1638
  g_main_loop_unref (loop);
 
1639
 
 
1640
  g_main_context_pop_thread_default (context);
 
1641
  g_main_context_unref (context);
 
1642
 
 
1643
  lookup_error = NULL;
 
1644
  if (g_simple_async_result_propagate_error (operation_result, &lookup_error))
 
1645
    {
 
1646
      translate_error (&lookup_error);
 
1647
      g_propagate_error (error, lookup_error);
 
1648
      g_object_unref (operation_result);
 
1649
      return FALSE;
 
1650
    }
 
1651
 
 
1652
  identity = g_simple_async_result_get_op_res_gpointer (operation_result);
 
1653
 
 
1654
  now = g_date_time_new_now_local ();
 
1655
  timestamp = goa_identity_service_identity_get_expiration_timestamp (identity);
 
1656
  expiration_time = g_date_time_new_from_unix_local (timestamp);
 
1657
  time_span = g_date_time_difference (expiration_time, now);
 
1658
 
 
1659
  time_span /= G_TIME_SPAN_SECOND;
 
1660
 
 
1661
  if (time_span < 0 || time_span > G_MAXINT)
 
1662
    time_span = 0;
 
1663
 
 
1664
  *out_expires_in = (int) time_span;
 
1665
 
 
1666
  g_date_time_unref (now);
 
1667
  g_date_time_unref (expiration_time);
 
1668
  g_object_unref (operation_result);
 
1669
 
 
1670
  return TRUE;
 
1671
}
 
1672
 
 
1673
static void
 
1674
goa_kerberos_provider_init (GoaKerberosProvider *provider)
 
1675
{
 
1676
}
 
1677
 
 
1678
static void
 
1679
goa_kerberos_provider_class_init (GoaKerberosProviderClass *kerberos_class)
 
1680
{
 
1681
  GoaProviderClass *provider_class;
 
1682
 
 
1683
  provider_class = GOA_PROVIDER_CLASS (kerberos_class);
 
1684
  provider_class->get_provider_type          = get_provider_type;
 
1685
  provider_class->get_provider_name          = get_provider_name;
 
1686
  provider_class->build_object               = build_object;
 
1687
  provider_class->add_account                = add_account;
 
1688
  provider_class->refresh_account            = refresh_account;
 
1689
  provider_class->show_account               = show_account;
 
1690
  provider_class->ensure_credentials_sync    = ensure_credentials_sync;
 
1691
}