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

« back to all changes in this revision

Viewing changes to src/goabackend/goaoauth2provider.c

  • Committer: Package Import Robot
  • Author(s): Andreas Henriksson, Laurent Bigonville, Andreas Henriksson
  • Date: 2014-05-16 11:42:52 UTC
  • mfrom: (1.1.28) (0.1.12 sid)
  • Revision ID: package-import@ubuntu.com-20140516114252-u5ect6mk6ht8i38x
Tags: 3.12.2-1
[ Laurent Bigonville ]
* debian/control.in: Recommends realmd package (Closes: #725965)

[ Andreas Henriksson ]
* New upstream release.
  - Removes chat support from Windows Live provider (XMPP gateway gone).
* Bump Standards-Version to 3.9.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
2
/*
3
 
 * Copyright (C) 2011, 2012 Red Hat, Inc.
 
3
 * Copyright (C) 2011, 2012, 2013, 2014 Red Hat, Inc.
4
4
 *
5
5
 * This library is free software; you can redistribute it and/or
6
6
 * modify it under the terms of the GNU Lesser General Public
13
13
 * Lesser General Public License for more details.
14
14
 *
15
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.
 
16
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19
17
 *
20
18
 * Author: David Zeuthen <davidz@redhat.com>
21
19
 *         Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
29
27
#include <libsoup/soup.h>
30
28
#include <json-glib/json-glib.h>
31
29
 
32
 
#include "goalogging.h"
33
30
#include "goaprovider.h"
34
31
#include "goautils.h"
35
32
#include "goawebview.h"
184
181
 * @element: A WebKitDOMHTMLInputElement
185
182
 *
186
183
 * Checks whether @element is the HTML UI element that the user can
187
 
 * use to enter her password.
 
184
 * use to enter her password. This can be used to offer a
 
185
 * #GoaPasswordBased interface by saving the user's
 
186
 * password. Providers usually frown upon doing this, so this is not
 
187
 * recommended.
188
188
 *
189
189
 * This is a virtual method where the default implementation returns
190
190
 * %FALSE.
252
252
 * @authorization_uri: An authorization URI.
253
253
 * @escaped_redirect_uri: An escaped redirect URI
254
254
 * @escaped_client_id: An escaped client id
255
 
 * @escaped_scope: The escaped scope.
 
255
 * @escaped_scope: (allow-none): The escaped scope or %NULL
256
256
 *
257
257
 * Builds the URI that can be opened in a web browser (or embedded web
258
258
 * browser widget) to start authenticating an user.
281
281
  g_return_val_if_fail (authorization_uri != NULL, NULL);
282
282
  g_return_val_if_fail (escaped_redirect_uri != NULL, NULL);
283
283
  g_return_val_if_fail (escaped_client_id != NULL, NULL);
284
 
  g_return_val_if_fail (escaped_scope != NULL, NULL);
285
284
  return GOA_OAUTH2_PROVIDER_GET_CLASS (provider)->build_authorization_uri (provider,
286
285
                                                                                    authorization_uri,
287
286
                                                                                    escaped_redirect_uri,
290
289
}
291
290
 
292
291
/**
 
292
 * goa_oauth2_provider_process_redirect_url:
 
293
 * @provider: A #GoaOAuth2Provider.
 
294
 * @redirect_url: A redirect URI from the web browser
 
295
 * @authorization_code: (out): Return location for access token
 
296
 * @error: Return location for error or %NULL
 
297
 *
 
298
 * Certain OAuth2-like, but not exactly <ulink
 
299
 * url="http://tools.ietf.org/html/draft-ietf-oauth-v2-15">OAuth2</ulink>,
 
300
 * providers do not follow the standard mechanisms for extracting the
 
301
 * access token or auth code from the redirect URI. They use some
 
302
 * non-standard technique to do so. This is a provider specific hook
 
303
 * to accommodate them and will only be used if implemented.
 
304
 *
 
305
 * This is a pure virtual method - a subclass must provide an
 
306
 * implementation if needed.
 
307
 *
 
308
 * Returns: %TRUE if @provider could process @redirect_url, %FALSE
 
309
 * otherwise.
 
310
 */
 
311
gboolean
 
312
goa_oauth2_provider_process_redirect_url (GoaOAuth2Provider  *provider,
 
313
                                          const gchar        *redirect_url,
 
314
                                          gchar             **authorization_code,
 
315
                                          GError            **error)
 
316
{
 
317
  g_return_val_if_fail (GOA_IS_OAUTH2_PROVIDER (provider), NULL);
 
318
  g_return_val_if_fail (redirect_url != NULL, NULL);
 
319
  g_return_val_if_fail (authorization_code != NULL, NULL);
 
320
  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
321
 
 
322
  return GOA_OAUTH2_PROVIDER_GET_CLASS (provider)->process_redirect_url (provider,
 
323
                                                                         redirect_url,
 
324
                                                                         authorization_code,
 
325
                                                                         error);
 
326
}
 
327
 
 
328
/**
293
329
 * goa_oauth2_provider_get_authorization_uri:
294
330
 * @provider: A #GoaOAuth2Provider.
295
331
 *
371
407
  return GOA_OAUTH2_PROVIDER_GET_CLASS (provider)->get_redirect_uri (provider);
372
408
}
373
409
 
 
410
/* ---------------------------------------------------------------------------------------------------- */
 
411
 
 
412
static const gchar *
 
413
goa_oauth2_provider_get_scope_default (GoaOAuth2Provider *provider)
 
414
{
 
415
  return NULL;
 
416
}
 
417
 
374
418
/**
375
419
 * goa_oauth2_provider_get_scope:
376
420
 * @provider: A #GoaOAuth2Provider.
379
423
 * url="http://tools.ietf.org/html/draft-ietf-oauth-v2-15#section-2.1.1">scope</ulink>
380
424
 * used when requesting authorization.
381
425
 *
382
 
 * This is a pure virtual method - a subclass must provide an
383
 
 * implementation.
 
426
 * This is a virtual method where the default implementation returns
 
427
 * %NULL.
384
428
 *
385
429
 * Returns: (transfer none): A string owned by @provider - do not free.
386
430
 */
391
435
  return GOA_OAUTH2_PROVIDER_GET_CLASS (provider)->get_scope (provider);
392
436
}
393
437
 
 
438
/* ---------------------------------------------------------------------------------------------------- */
 
439
 
394
440
/**
395
441
 * goa_oauth2_provider_get_client_id:
396
442
 * @provider: A #GoaOAuth2Provider.
669
715
      GHashTable *hash;
670
716
      const gchar *expires_in_str;
671
717
 
672
 
      goa_debug ("Response is not JSON - possibly old OAuth2 implementation");
 
718
      g_debug ("Response is not JSON - possibly old OAuth2 implementation");
673
719
 
674
720
      hash = soup_form_decode (payload);
675
721
      ret_access_token = g_strdup (g_hash_table_lookup (hash, "access_token"));
676
722
      if (ret_access_token == NULL)
677
723
        {
678
 
          goa_warning ("Did not find access_token in non-JSON data");
 
724
          g_warning ("Did not find access_token in non-JSON data");
679
725
          g_set_error (error,
680
726
                       GOA_ERROR,
681
727
                       GOA_ERROR_FAILED,
702
748
      parser = json_parser_new ();
703
749
      if (!json_parser_load_from_data (parser, payload, payload_length, &tokens_error))
704
750
        {
705
 
          goa_warning ("json_parser_load_from_data() failed: %s (%s, %d)",
706
 
                       tokens_error->message,
707
 
                       g_quark_to_string (tokens_error->domain),
708
 
                       tokens_error->code);
 
751
          g_warning ("json_parser_load_from_data() failed: %s (%s, %d)",
 
752
                     tokens_error->message,
 
753
                     g_quark_to_string (tokens_error->domain),
 
754
                     tokens_error->code);
709
755
          g_set_error (error,
710
756
                       GOA_ERROR,
711
757
                       GOA_ERROR_FAILED,
717
763
      ret_access_token = g_strdup (json_object_get_string_member (object, "access_token"));
718
764
      if (ret_access_token == NULL)
719
765
        {
720
 
          goa_warning ("Did not find access_token in JSON data");
 
766
          g_warning ("Did not find access_token in JSON data");
721
767
          g_set_error (error,
722
768
                       GOA_ERROR,
723
769
                       GOA_ERROR_FAILED,
898
944
  fragment = soup_uri_get_fragment (uri);
899
945
  query = soup_uri_get_query (uri);
900
946
 
901
 
  /* Two cases:
902
 
   * 1) we can either have the access_token and other information
 
947
  /* Three cases:
 
948
   * 1) we can either have the backend handle the URI for us, or
 
949
   * 2) we can either have the access_token and other information
903
950
   *    directly in the fragment part of the URI, or
904
 
   * 2) the auth code can be in the query part of the URI, with which
 
951
   * 3) the auth code can be in the query part of the URI, with which
905
952
   *    we'll obtain the token later.
906
953
   */
 
954
  if (GOA_OAUTH2_PROVIDER_GET_CLASS (provider)->process_redirect_url)
 
955
    {
 
956
      gchar *url;
 
957
 
 
958
      url = soup_uri_to_string (uri, FALSE);
 
959
      if (!goa_oauth2_provider_process_redirect_url (provider, url, &priv->access_token, &priv->error))
 
960
        {
 
961
          g_prefix_error (&priv->error, _("Authorization response: "));
 
962
          priv->error->domain = GOA_ERROR;
 
963
          priv->error->code = GOA_ERROR_NOT_AUTHORIZED;
 
964
          response_id = GTK_RESPONSE_CLOSE;
 
965
        }
 
966
      else
 
967
        response_id = GTK_RESPONSE_OK;
 
968
 
 
969
      g_free (url);
 
970
      goto ignore_request;
 
971
    }
 
972
 
907
973
  if (fragment != NULL)
908
974
    {
909
975
      /* fragment is encoded into a key/value pairs for the token and
962
1028
      g_set_error (&priv->error,
963
1029
                   GOA_ERROR,
964
1030
                   GOA_ERROR_NOT_AUTHORIZED,
965
 
                   _("Authorization response was \"%s\""),
 
1031
                   _("Authorization response: %s"),
966
1032
                   oauth2_error);
967
1033
      response_id = GTK_RESPONSE_CLOSE;
968
1034
    }
1003
1069
  gboolean ret;
1004
1070
  gchar *url;
1005
1071
  GtkWidget *grid;
 
1072
  const gchar *scope;
1006
1073
  gchar *escaped_redirect_uri;
1007
1074
  gchar *escaped_client_id;
1008
1075
  gchar *escaped_scope;
1034
1101
  /* TODO: use oauth2_proxy_build_login_url_full() */
1035
1102
  escaped_redirect_uri = g_uri_escape_string (goa_oauth2_provider_get_redirect_uri (provider), NULL, TRUE);
1036
1103
  escaped_client_id = g_uri_escape_string (goa_oauth2_provider_get_client_id (provider), NULL, TRUE);
1037
 
  escaped_scope = g_uri_escape_string (goa_oauth2_provider_get_scope (provider), NULL, TRUE);
 
1104
  scope = goa_oauth2_provider_get_scope (provider);
 
1105
  if (scope != NULL)
 
1106
    escaped_scope = g_uri_escape_string (goa_oauth2_provider_get_scope (provider), NULL, TRUE);
 
1107
  else
 
1108
    escaped_scope = NULL;
1038
1109
  url = goa_oauth2_provider_build_authorization_uri (provider,
1039
1110
                                                     goa_oauth2_provider_get_authorization_uri (provider),
1040
1111
                                                     escaped_redirect_uri,
1073
1144
      gtk_widget_grab_focus (entry);
1074
1145
      gtk_widget_show_all (GTK_WIDGET (vbox));
1075
1146
 
1076
 
      gtk_dialog_add_button (dialog, GTK_STOCK_OK, GTK_RESPONSE_OK);
 
1147
      gtk_dialog_add_button (dialog, _("_OK"), GTK_RESPONSE_OK);
1077
1148
      gtk_dialog_set_default_response (dialog, GTK_RESPONSE_OK);
1078
1149
      gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_OK, FALSE);
1079
1150
      g_signal_connect (entry, "changed", G_CALLBACK (on_entry_changed), provider);
1356
1427
  dialog = gtk_dialog_new_with_buttons (NULL,
1357
1428
                                        parent,
1358
1429
                                        GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1359
 
                                        GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
 
1430
                                        _("_Cancel"), GTK_RESPONSE_REJECT,
1360
1431
                                        NULL);
1361
1432
  gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
1362
1433
  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
1386
1457
      g_set_error (error,
1387
1458
                   GOA_ERROR,
1388
1459
                   GOA_ERROR_FAILED,
1389
 
                   _("Was asked to login as %s, but logged in as %s"),
 
1460
                   _("Was asked to log in as %s, but logged in as %s"),
1390
1461
                   existing_identity,
1391
1462
                   priv->identity);
1392
1463
      goto out;
1552
1623
  /* if we can't refresh the token, just return it no matter what */
1553
1624
  if (refresh_token == NULL)
1554
1625
    {
1555
 
      goa_debug ("Returning locally cached credentials that cannot be refreshed");
 
1626
      g_debug ("Returning locally cached credentials that cannot be refreshed");
1556
1627
      success = TRUE;
1557
1628
      goto out;
1558
1629
    }
1563
1634
   */
1564
1635
  if (!force_refresh && access_token_expires_in > 10*60)
1565
1636
    {
1566
 
      goa_debug ("Returning locally cached credentials (expires in %d seconds)", access_token_expires_in);
 
1637
      g_debug ("Returning locally cached credentials (expires in %d seconds)", access_token_expires_in);
1567
1638
      success = TRUE;
1568
1639
      goto out;
1569
1640
    }
1570
1641
 
1571
 
  goa_debug ("Refreshing locally cached credentials (expires in %d seconds, force_refresh=%d)", access_token_expires_in, force_refresh);
 
1642
  g_debug ("Refreshing locally cached credentials (expires in %d seconds, force_refresh=%d)", access_token_expires_in, force_refresh);
1572
1643
 
1573
1644
  /* Otherwise, refresh it */
1574
1645
  old_refresh_token = refresh_token; refresh_token = NULL;
1798
1869
 
1799
1870
  klass->build_authorization_uri  = goa_oauth2_provider_build_authorization_uri_default;
1800
1871
  klass->get_token_uri            = goa_oauth2_provider_get_token_uri_default;
 
1872
  klass->get_scope                = goa_oauth2_provider_get_scope_default;
1801
1873
  klass->get_use_external_browser = goa_oauth2_provider_get_use_external_browser_default;
1802
1874
  klass->get_use_mobile_browser   = goa_oauth2_provider_get_use_mobile_browser_default;
1803
1875
  klass->is_password_node         = goa_oauth2_provider_is_password_node_default;