diff options
author | Ray Strode <rstrode@redhat.com> | 2023-05-16 15:01:23 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2023-05-16 15:17:07 -0400 |
commit | e71e10d7f1267c05ef022fa3d1d4429468baf653 (patch) | |
tree | 1e15712c89c76e597b19222e5203f2b04d9b838b | |
parent | 19445fae720d98bea4cd91332fe2b7c8a0434daf (diff) | |
download | gnome-online-accounts-firefox-instead-of-webkit-experiment.tar.gz |
wip! goaoauth2provider: Add proof of concept hack to test firefox instead of webkitfirefox-instead-of-webkit-experiment
This quick hack uses firefox instead of webkit to show the feasibility
of complying with google's new security guidelines regarding oauth2
authentication:
https://developers.googleblog.com/2020/08/guidance-for-our-effort-to-block-less-secure-browser-and-apps.html
It's not shippable as-is obviously. Also, it requires manually creating
a url handler:
╎❯ cat ~/.local/share/applications/gnome-oauth2-provider.desktop
[Desktop Entry]
Name=GNOME OAuth2 Provider
Exec=/bin/bash -c "echo %u > /tmp/url"
Type=Application
MimeType=x-scheme-handler/gnome-oauth2-provider;x-scheme-handler/com.googleusercontent.apps.44438659992-7kgjeitenc16ssihbtdjbgguch7ju55s
and running:
╎❯ update-desktop-database ~/.local/share/applications
Before this can land, the url handler will need to do something
more intelligent...perhaps:
```
secret_password_store_sync(
&schema,
SECRET_COLLECTION_SESSION,
"Requested URI for com.googleusercontent.apps.44438659992-7kgjeitenc16ssihbtdjbgguch7ju55s",
requested_uri,
cancellable,
&error,
"uri", requested_uri,
NULL
);
```
to store the requested uri in the transient session keyring.
And then gnome-online-accounts goabackend would need to listen for CollectionChanged on the session
collection to know when the secret arrived.
It's not clear how we would handle the user closing the browser without
doing anything. I guess we would need to wrap things up on the
control-center side from a user experience point of view as soon as firefox was launched.
https://gitlab.gnome.org/GNOME/gnome-online-accounts/-/issues/157
-rw-r--r-- | src/goabackend/goaoauth2provider.c | 122 |
1 files changed, 71 insertions, 51 deletions
diff --git a/src/goabackend/goaoauth2provider.c b/src/goabackend/goaoauth2provider.c index d739dec..d09d3d5 100644 --- a/src/goabackend/goaoauth2provider.c +++ b/src/goabackend/goaoauth2provider.c @@ -81,6 +81,7 @@ struct _GoaOAuth2ProviderPrivate gchar *identity; gchar *presentation_identity; gchar *password; + char *requested_uri; }; G_LOCK_DEFINE_STATIC (provider_lock); @@ -757,42 +758,19 @@ on_web_view_password_submit (GoaWebView *web_view, const gchar *password, gpoint } static gboolean -on_web_view_decide_policy (WebKitWebView *web_view, - WebKitPolicyDecision *decision, - WebKitPolicyDecisionType decision_type, - gpointer user_data) +parse_requested_uri (GoaOAuth2Provider *self, + const gchar *requested_uri) { - GoaOAuth2Provider *self = GOA_OAUTH2_PROVIDER (user_data); GoaOAuth2ProviderPrivate *priv; GHashTable *key_value_pairs; - WebKitNavigationAction *action; - WebKitURIRequest *request; GUri *uri = NULL; const gchar *fragment; const gchar *oauth2_error; const gchar *query; const gchar *redirect_uri; - const gchar *requested_uri; - gint response_id = GTK_RESPONSE_NONE; priv = goa_oauth2_provider_get_instance_private (self); - if (decision_type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) - goto default_behaviour; - - if (goa_oauth2_provider_decide_navigation_policy (self, - web_view, - WEBKIT_NAVIGATION_POLICY_DECISION (decision))) - { - response_id = 0; - goto ignore_request; - } - - /* TODO: use oauth2_proxy_extract_access_token() */ - - action = webkit_navigation_policy_decision_get_navigation_action (WEBKIT_NAVIGATION_POLICY_DECISION (decision)); - request = webkit_navigation_action_get_request (action); - requested_uri = webkit_uri_request_get_uri (request); redirect_uri = goa_oauth2_provider_get_redirect_uri (self); if (!g_str_has_prefix (requested_uri, redirect_uri)) goto default_behaviour; @@ -818,10 +796,7 @@ on_web_view_decide_policy (WebKitWebView *web_view, g_prefix_error (&priv->error, _("Authorization response: ")); priv->error->domain = GOA_ERROR; priv->error->code = GOA_ERROR_NOT_AUTHORIZED; - response_id = GTK_RESPONSE_CLOSE; } - else - response_id = GTK_RESPONSE_OK; g_free (url); goto ignore_request; @@ -850,8 +825,6 @@ on_web_view_decide_policy (WebKitWebView *web_view, priv->access_token_expires_in = atoi (expires_in_str); priv->refresh_token = g_strdup (g_hash_table_lookup (key_value_pairs, "refresh_token")); - - response_id = GTK_RESPONSE_OK; } g_hash_table_unref (key_value_pairs); } @@ -864,9 +837,6 @@ on_web_view_decide_policy (WebKitWebView *web_view, key_value_pairs = soup_form_decode (query); priv->authorization_code = g_strdup (g_hash_table_lookup (key_value_pairs, "code")); - if (priv->authorization_code != NULL) - response_id = GTK_RESPONSE_OK; - g_hash_table_unref (key_value_pairs); } @@ -878,16 +848,13 @@ on_web_view_decide_policy (WebKitWebView *web_view, */ key_value_pairs = soup_form_decode (query); oauth2_error = (const gchar *) g_hash_table_lookup (key_value_pairs, "error"); - if (g_strcmp0 (oauth2_error, GOA_OAUTH2_ACCESS_DENIED) == 0) - response_id = GTK_RESPONSE_CANCEL; - else + if (g_strcmp0 (oauth2_error, GOA_OAUTH2_ACCESS_DENIED) != 0) { g_set_error (&priv->error, GOA_ERROR, GOA_ERROR_NOT_AUTHORIZED, _("Authorization response: %s"), oauth2_error); - response_id = GTK_RESPONSE_CLOSE; } g_hash_table_unref (key_value_pairs); goto ignore_request; @@ -895,13 +862,52 @@ on_web_view_decide_policy (WebKitWebView *web_view, ignore_request: if (uri) g_uri_unref (uri); - g_assert (response_id != GTK_RESPONSE_NONE); - if (response_id < 0) - gtk_dialog_response (priv->dialog, response_id); + return TRUE; + + default_behaviour: + return FALSE; +} + +static gboolean +on_web_view_decide_policy (WebKitWebView *web_view, + WebKitPolicyDecision *decision, + WebKitPolicyDecisionType decision_type, + gpointer user_data) +{ + GoaOAuth2Provider *self = GOA_OAUTH2_PROVIDER (user_data); + GoaOAuth2ProviderPrivate *priv; + WebKitNavigationAction *action; + WebKitURIRequest *request; + const gchar *requested_uri; + + priv = goa_oauth2_provider_get_instance_private (self); + + if (decision_type != WEBKIT_POLICY_DECISION_TYPE_NAVIGATION_ACTION) + goto default_behaviour; + + if (goa_oauth2_provider_decide_navigation_policy (self, + web_view, + WEBKIT_NAVIGATION_POLICY_DECISION (decision))) + { + goto ignore_request; + } + + /* TODO: use oauth2_proxy_extract_access_token() */ + + action = webkit_navigation_policy_decision_get_navigation_action (WEBKIT_NAVIGATION_POLICY_DECISION (decision)); + request = webkit_navigation_action_get_request (action); + requested_uri = webkit_uri_request_get_uri (request); + + if (!parse_requested_uri (self, requested_uri)) + goto ignore_request; + + ignore_request: + gtk_dialog_response (priv->dialog, GTK_RESPONSE_CLOSE); webkit_policy_decision_ignore (decision); return TRUE; default_behaviour: + gtk_dialog_response (priv->dialog, GTK_RESPONSE_OK); return FALSE; } @@ -973,19 +979,33 @@ get_tokens_and_identity (GoaOAuth2Provider *self, if (goa_oauth2_provider_get_use_mobile_browser (self)) goa_web_view_fake_mobile (GOA_WEB_VIEW (web_view)); - webkit_web_view_load_uri (WEBKIT_WEB_VIEW (embed), url); - g_signal_connect (embed, - "decide-policy", - G_CALLBACK (on_web_view_decide_policy), - self); - g_signal_connect (web_view, "deny-click", G_CALLBACK (on_web_view_deny_click), self); - g_signal_connect (web_view, "password-submit", G_CALLBACK (on_web_view_password_submit), self); + unlink ("/tmp/url"); + system (g_strdup_printf ("firefox '%s'", url)); + while (!g_file_test ("/tmp/url", G_FILE_TEST_EXISTS)) + g_usleep (G_USEC_PER_SEC); - gtk_container_add (GTK_CONTAINER (grid), web_view); - gtk_window_set_default_size (GTK_WINDOW (dialog), -1, -1); + g_file_get_contents ("/tmp/url", &priv->requested_uri, NULL, NULL); - gtk_widget_show_all (GTK_WIDGET (vbox)); - gtk_dialog_run (GTK_DIALOG (dialog)); + if (priv->requested_uri != NULL) + { + parse_requested_uri (self, priv->requested_uri); + } + else + { + webkit_web_view_load_uri (WEBKIT_WEB_VIEW (embed), url); + g_signal_connect (embed, + "decide-policy", + G_CALLBACK (on_web_view_decide_policy), + self); + g_signal_connect (web_view, "deny-click", G_CALLBACK (on_web_view_deny_click), self); + g_signal_connect (web_view, "password-submit", G_CALLBACK (on_web_view_password_submit), self); + + gtk_container_add (GTK_CONTAINER (grid), web_view); + gtk_window_set_default_size (GTK_WINDOW (dialog), -1, -1); + + gtk_widget_show_all (GTK_WIDGET (vbox)); + gtk_dialog_run (GTK_DIALOG (dialog)); + } /* We can have either the auth code, with which we'll obtain the token, or * the token directly if we are using a client side flow, since we don't |