From ae13e31510d0ff59df21336b30adeb4d5f22c4e7 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 17 Oct 2019 17:00:32 +0200 Subject: [PATCH] transaction: Request required tokens from configured authenticator When we need a bearer token, look up the configured authenticator for the remote and ask it for tokens. Also updates the test-auth test with to use the new test authenticator instead of the previous env var hack. --- common/flatpak-transaction.c | 103 ++++++++++++++++++++++++++++++----- tests/test-auth.sh | 27 ++++++--- 2 files changed, 109 insertions(+), 21 deletions(-) diff --git a/common/flatpak-transaction.c b/common/flatpak-transaction.c index e96ccca5..5c4a90dd 100644 --- a/common/flatpak-transaction.c +++ b/common/flatpak-transaction.c @@ -28,6 +28,7 @@ #include "flatpak-installation-private.h" #include "flatpak-utils-private.h" #include "flatpak-error.h" +#include "flatpak-auth-private.h" /** * SECTION:flatpak-transaction @@ -2599,6 +2600,24 @@ resolve_all_ops (FlatpakTransaction *self, return TRUE; } +typedef struct { + FlatpakTransaction *transaction; + gboolean done; + guint response; + GVariant *results; +} RequestTokensData; + + +static void +request_tokens_response (FlatpakAuthenticatorRequest *object, + guint response, + GVariant *results, + RequestTokensData *data) +{ + data->response = response; + data->results = g_variant_ref (results); + data->done = TRUE; +} static gboolean request_tokens_for_remote (FlatpakTransaction *self, @@ -2607,34 +2626,90 @@ request_tokens_for_remote (FlatpakTransaction *self, GCancellable *cancellable, GError **error) { - g_autoptr(GString) refs_as_str = g_string_new (""); + FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); + g_autofree char *refs_as_str = NULL; GList *l; - const char *token; + g_autoptr(GPtrArray) refs = g_ptr_array_new (); + g_autoptr(AutoFlatpakAuthenticatorRequest) request = NULL; + g_autoptr(AutoFlatpakAuthenticator) authenticator = NULL; + g_autoptr(GMainContextPopDefault) context = NULL; + RequestTokensData data = { self }; + g_autoptr(GVariant) tokens = NULL; + g_autoptr(GVariant) results = NULL; for (l = ops; l != NULL; l = l->next) { FlatpakTransactionOperation *op = l->data; + g_ptr_array_add (refs, op->ref); + } + g_ptr_array_add (refs, NULL); - if (l != ops) - g_string_append (refs_as_str, ", "); - g_string_append (refs_as_str, op->ref); + refs_as_str = g_strjoinv (", ", (char **)refs->pdata); + g_debug ("Requesting tokens for remote %s, refs: %s", remote, refs_as_str); + + context = flatpak_main_context_new_default (); + + authenticator = flatpak_auth_new_for_remote (priv->dir, remote, cancellable, error); + if (authenticator == NULL) + return FALSE; + + request = flatpak_auth_create_request (authenticator, cancellable, error); + if (request == NULL) + return FALSE; + + g_signal_connect (request, "response", (GCallback)request_tokens_response, &data); + + if (!flatpak_auth_request_ref_tokens (authenticator, request, (const char **)refs->pdata, cancellable, error)) + return FALSE; + + while (!data.done) + g_main_context_iteration (context, TRUE); + + results = data.results; /* Make sure its freed as needed */ + + { + g_autofree char *results_str = g_variant_print (results, FALSE); + g_debug ("Response from request_tokens: %d - %s\n", data.response, results_str); + } + + if (data.response == FLATPAK_AUTH_RESPONSE_CANCELLED) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "User cancelled authentication request"); + return FALSE; } - g_debug ("Requesting tokens for remote %s, refs: %s", remote, refs_as_str->str); + if (data.response != FLATPAK_AUTH_RESPONSE_OK) + return flatpak_fail (error, "Failed to get tokens for ref"); - /* FIXME: This is just some temporary testing code and will be - replaces with a callout later. */ - token = g_getenv ("FLATPAK_TEST_TOKEN"); - if (token == NULL) - token = "default-token"; - - g_debug ("Got token %s", token); + tokens = g_variant_lookup_value (results, "tokens", G_VARIANT_TYPE ("a{sas}")); + if (tokens == NULL) + return flatpak_fail (error, "Authenticator didn't send requested tokens"); for (l = ops; l != NULL; l = l->next) { FlatpakTransactionOperation *op = l->data; + GVariantIter iter; + const char *token = NULL; + const char *token_for_refs; + g_autofree const char **refs; - op->resolved_token = g_strdup (token); + g_variant_iter_init (&iter, tokens); + while (g_variant_iter_next (&iter, "{&s^a&s}", &token_for_refs, &refs)) + { + if (g_strv_contains (refs, op->ref)) + { + token = token_for_refs; + break; + } + } + + if (token == NULL) + return flatpak_fail (error, "Authenticator didn't send tokens for ref"); + + /* Allow sending empty tokens to mean no token needed */ + + op->resolved_token = *token == 0 ? NULL : g_strdup (token); op->requested_token = TRUE; } diff --git a/tests/test-auth.sh b/tests/test-auth.sh index a715dc12..0c691b3d 100755 --- a/tests/test-auth.sh +++ b/tests/test-auth.sh @@ -47,7 +47,6 @@ assert_failed_with_401 () { fi } - # Mark as need token, even though the app doesn't have token-type set # We should not be able to install this because we will not present # the token unnecessarily @@ -62,26 +61,38 @@ assert_failed_with_401 EXPORT_ARGS="--token-type=2" make_updated_app mark_need_token app/org.test.Hello/$ARCH/master the-secret +# Install with no authenticator +if ${FLATPAK} ${U} install -y test-repo org.test.Hello master 2> install-error-log; then + assert_not_reached "Should not be able to install without authenticator" +fi +assert_file_has_content install-error-log "No authenticator configured for remote" + +${FLATPAK} ${U} remote-modify test-repo --authenticator-name org.flatpak.Authenticator.test + # Install with wrong token -if FLATPAK_TEST_TOKEN=not-the-secret ${FLATPAK} ${U} install -y test-repo org.test.Hello master 2> install-error-log; then +echo -n not-the-secret > ${XDG_RUNTIME_DIR}/required-token +if ${FLATPAK} ${U} install -y test-repo org.test.Hello master 2> install-error-log; then assert_not_reached "Should not be able to install with wrong secret" fi assert_failed_with_401 # Install with right token -FLATPAK_TEST_TOKEN=the-secret ${FLATPAK} ${U} install -y test-repo org.test.Hello master +echo -n the-secret > ${XDG_RUNTIME_DIR}/required-token +${FLATPAK} ${U} install -y test-repo org.test.Hello master EXPORT_ARGS="--token-type=2" make_updated_app test "" master UPDATE2 mark_need_token app/org.test.Hello/$ARCH/master the-secret # Update with wrong token -if FLATPAK_TEST_TOKEN=not-the-secret ${FLATPAK} ${U} update -y org.test.Hello 2> install-error-log; then +echo -n not-the-secret > ${XDG_RUNTIME_DIR}/required-token +if ${FLATPAK} ${U} update -y org.test.Hello 2> install-error-log; then assert_not_reached "Should not be able to install with wrong secret" fi assert_failed_with_401 # Update with right token -FLATPAK_TEST_TOKEN=the-secret ${FLATPAK} ${U} update -y org.test.Hello +echo -n the-secret > ${XDG_RUNTIME_DIR}/required-token +${FLATPAK} ${U} update -y org.test.Hello echo "ok installed build-exported token-type app" @@ -95,12 +106,14 @@ $FLATPAK build-commit-from ${FL_GPGARGS} --token-type=2 --disable-fsync --src-r mark_need_token app/org.test.Hello/$ARCH/copy the-secret # Install with wrong token -if FLATPAK_TEST_TOKEN=not-the-secret ${FLATPAK} ${U} install -y test-repo org.test.Hello//copy 2> install-error-log; then +echo -n not-the-secret > ${XDG_RUNTIME_DIR}/required-token +if ${FLATPAK} ${U} install -y test-repo org.test.Hello//copy 2> install-error-log; then assert_not_reached "Should not be able to install with wrong secret" fi assert_failed_with_401 # Install with right token -FLATPAK_TEST_TOKEN=the-secret ${FLATPAK} ${U} install -y test-repo org.test.Hello//copy +echo -n the-secret > ${XDG_RUNTIME_DIR}/required-token +${FLATPAK} ${U} install -y test-repo org.test.Hello//copy echo "ok installed build-commit-from token-type app"