summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRay Strode <rstrode@redhat.com>2023-05-16 15:01:23 -0400
committerRay Strode <rstrode@redhat.com>2023-05-16 15:17:07 -0400
commite71e10d7f1267c05ef022fa3d1d4429468baf653 (patch)
tree1e15712c89c76e597b19222e5203f2b04d9b838b
parent19445fae720d98bea4cd91332fe2b7c8a0434daf (diff)
downloadgnome-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.c122
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