1
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3
* Copyright (C) 2011, 2012 Red Hat, Inc.
3
* Copyright (C) 2011, 2012, 2013, 2014 Red Hat, Inc.
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.
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/>.
20
18
* Author: David Zeuthen <davidz@redhat.com>
21
19
* Cosimo Alfarano <cosimo.alfarano@collabora.co.uk>
184
181
* @element: A WebKitDOMHTMLInputElement
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
189
189
* This is a virtual method where the default implementation returns
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
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,
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
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.
305
* This is a pure virtual method - a subclass must provide an
306
* implementation if needed.
308
* Returns: %TRUE if @provider could process @redirect_url, %FALSE
312
goa_oauth2_provider_process_redirect_url (GoaOAuth2Provider *provider,
313
const gchar *redirect_url,
314
gchar **authorization_code,
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);
322
return GOA_OAUTH2_PROVIDER_GET_CLASS (provider)->process_redirect_url (provider,
293
329
* goa_oauth2_provider_get_authorization_uri:
294
330
* @provider: A #GoaOAuth2Provider.
371
407
return GOA_OAUTH2_PROVIDER_GET_CLASS (provider)->get_redirect_uri (provider);
410
/* ---------------------------------------------------------------------------------------------------- */
413
goa_oauth2_provider_get_scope_default (GoaOAuth2Provider *provider)
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.
382
* This is a pure virtual method - a subclass must provide an
426
* This is a virtual method where the default implementation returns
385
429
* Returns: (transfer none): A string owned by @provider - do not free.
391
435
return GOA_OAUTH2_PROVIDER_GET_CLASS (provider)->get_scope (provider);
438
/* ---------------------------------------------------------------------------------------------------- */
395
441
* goa_oauth2_provider_get_client_id:
396
442
* @provider: A #GoaOAuth2Provider.
669
715
GHashTable *hash;
670
716
const gchar *expires_in_str;
672
goa_debug ("Response is not JSON - possibly old OAuth2 implementation");
718
g_debug ("Response is not JSON - possibly old OAuth2 implementation");
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)
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,
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))
705
goa_warning ("json_parser_load_from_data() failed: %s (%s, %d)",
706
tokens_error->message,
707
g_quark_to_string (tokens_error->domain),
751
g_warning ("json_parser_load_from_data() failed: %s (%s, %d)",
752
tokens_error->message,
753
g_quark_to_string (tokens_error->domain),
709
755
g_set_error (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)
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,
723
769
GOA_ERROR_FAILED,
898
944
fragment = soup_uri_get_fragment (uri);
899
945
query = soup_uri_get_query (uri);
902
* 1) we can either have the access_token and other information
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.
954
if (GOA_OAUTH2_PROVIDER_GET_CLASS (provider)->process_redirect_url)
958
url = soup_uri_to_string (uri, FALSE);
959
if (!goa_oauth2_provider_process_redirect_url (provider, url, &priv->access_token, &priv->error))
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;
967
response_id = GTK_RESPONSE_OK;
907
973
if (fragment != NULL)
909
975
/* fragment is encoded into a key/value pairs for the token and
962
1028
g_set_error (&priv->error,
964
1030
GOA_ERROR_NOT_AUTHORIZED,
965
_("Authorization response was \"%s\""),
1031
_("Authorization response: %s"),
967
1033
response_id = GTK_RESPONSE_CLOSE;
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);
1106
escaped_scope = g_uri_escape_string (goa_oauth2_provider_get_scope (provider), NULL, TRUE);
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));
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,
1358
1429
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1359
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1430
_("_Cancel"), GTK_RESPONSE_REJECT,
1361
1432
gtk_container_set_border_width (GTK_CONTAINER (dialog), 12);
1362
1433
gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
1552
1623
/* if we can't refresh the token, just return it no matter what */
1553
1624
if (refresh_token == NULL)
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;
1564
1635
if (!force_refresh && access_token_expires_in > 10*60)
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;
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);
1573
1644
/* Otherwise, refresh it */
1574
1645
old_refresh_token = refresh_token; refresh_token = NULL;
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;