From 36039759e2fbcadfb7841a035e98879e478ff8fb Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 26 Sep 2017 22:02:25 -0400 Subject: [PATCH] pull: Add support for basic auth This has been requested a few times for people delivering OSTree content and wanting to do access control. --- Makefile-tests.am | 1 + src/libostree/ostree-fetcher-curl.c | 12 +++++-- src/ostree/ostree-trivial-httpd.c | 18 ++++++++++ tests/test-pull-basicauth.sh | 55 +++++++++++++++++++++++++++++ 4 files changed, 83 insertions(+), 3 deletions(-) create mode 100755 tests/test-pull-basicauth.sh diff --git a/Makefile-tests.am b/Makefile-tests.am index f5a65278..fc2f2d91 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -84,6 +84,7 @@ _installed_or_uninstalled_test_scripts = \ tests/test-pull-metalink.sh \ tests/test-pull-summary-sigs.sh \ tests/test-pull-resume.sh \ + tests/test-pull-basicauth.sh \ tests/test-pull-repeated.sh \ tests/test-pull-untrusted.sh \ tests/test-pull-override-url.sh \ diff --git a/src/libostree/ostree-fetcher-curl.c b/src/libostree/ostree-fetcher-curl.c index 294b2078..fdf8a2ef 100644 --- a/src/libostree/ostree-fetcher-curl.c +++ b/src/libostree/ostree-fetcher-curl.c @@ -261,9 +261,8 @@ destroy_and_unref_source (GSource *source) } static char * -request_get_uri (FetcherRequest *req, guint idx) +request_get_uri (FetcherRequest *req, SoupURI *baseuri) { - SoupURI *baseuri = req->mirrorlist->pdata[idx]; if (!req->filename) return soup_uri_to_string (baseuri, FALSE); { g_autofree char *uristr = soup_uri_to_string (baseuri, FALSE); @@ -715,7 +714,8 @@ initiate_next_curl_request (FetcherRequest *req, g_assert_cmpint (req->idx, <, req->mirrorlist->len); - { g_autofree char *uri = request_get_uri (req, req->idx); + SoupURI *baseuri = req->mirrorlist->pdata[req->idx]; + { g_autofree char *uri = request_get_uri (req, baseuri); curl_easy_setopt (req->easy, CURLOPT_URL, uri); } @@ -771,6 +771,12 @@ initiate_next_curl_request (FetcherRequest *req, if ((self->config_flags & OSTREE_FETCHER_FLAGS_TRANSFER_GZIP) > 0) curl_easy_setopt (req->easy, CURLOPT_ACCEPT_ENCODING, ""); + /* If we have e.g. basic auth in the URL string, let's honor that */ + const char *username = soup_uri_get_user (baseuri); + curl_easy_setopt (req->easy, CURLOPT_USERNAME, username); + const char *password = soup_uri_get_password (baseuri); + curl_easy_setopt (req->easy, CURLOPT_PASSWORD, password); + /* We should only speak HTTP; TODO: only enable file if specified */ curl_easy_setopt (req->easy, CURLOPT_PROTOCOLS, (long)(CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FILE)); /* Picked the current version in F25 as of 20170127, since diff --git a/src/ostree/ostree-trivial-httpd.c b/src/ostree/ostree-trivial-httpd.c index 1b7aa2a2..5d3a004e 100644 --- a/src/ostree/ostree-trivial-httpd.c +++ b/src/ostree/ostree-trivial-httpd.c @@ -50,6 +50,7 @@ static int opt_random_408s_max = 100; static gint opt_port = 0; static gchar **opt_expected_cookies; static gchar **opt_expected_headers; +static gboolean opt_require_basic_auth; static guint emitted_random_500s_count = 0; static guint emitted_random_408s_count = 0; @@ -71,6 +72,7 @@ static GOptionEntry options[] = { { "port", 'P', 0, G_OPTION_ARG_INT, &opt_port, "Use the specified TCP port", "PORT" }, { "port-file", 'p', 0, G_OPTION_ARG_FILENAME, &opt_port_file, "Write port number to PATH (- for standard output)", "PATH" }, { "force-range-requests", 0, 0, G_OPTION_ARG_NONE, &opt_force_ranges, "Force range requests by only serving half of files", NULL }, + { "require-basic-auth", 0, 0, G_OPTION_ARG_NONE, &opt_require_basic_auth, "Require username foouser, password barpw", NULL }, { "random-500s", 0, 0, G_OPTION_ARG_INT, &opt_random_500s_percentage, "Generate random HTTP 500 errors approximately for PERCENTAGE requests", "PERCENTAGE" }, { "random-500s-max", 0, 0, G_OPTION_ARG_INT, &opt_random_500s_max, "Limit HTTP 500 errors to MAX (default 100)", "MAX" }, { "random-408s", 0, 0, G_OPTION_ARG_INT, &opt_random_408s_percentage, "Generate random HTTP 408 errors approximately for PERCENTAGE requests", "PERCENTAGE" }, @@ -474,6 +476,13 @@ httpd_callback (SoupServer *server, SoupMessage *msg, soup_message_set_status (msg, SOUP_STATUS_NOT_IMPLEMENTED); } +static gboolean +basic_auth_callback (SoupAuthDomain *auth_domain, SoupMessage *msg, + const char *username, const char *password, gpointer data) +{ + return g_str_equal (username, "foouser") && g_str_equal (password, "barpw"); +} + static void on_dir_changed (GFileMonitor *mon, GFile *file, @@ -571,6 +580,15 @@ run (int argc, char **argv, GCancellable *cancellable, GError **error) SOUP_SERVER_SERVER_HEADER, "ostree-httpd ", NULL); #endif + if (opt_require_basic_auth) + { + glnx_unref_object SoupAuthDomain *auth_domain = + soup_auth_domain_basic_new (SOUP_AUTH_DOMAIN_REALM, "auth-test", + SOUP_AUTH_DOMAIN_ADD_PATH, "/", + SOUP_AUTH_DOMAIN_BASIC_AUTH_CALLBACK, basic_auth_callback, + NULL); + soup_server_add_auth_domain (server, auth_domain); + } soup_server_add_handler (server, NULL, httpd_callback, app, NULL); if (opt_port_file) diff --git a/tests/test-pull-basicauth.sh b/tests/test-pull-basicauth.sh new file mode 100755 index 00000000..4a2622a7 --- /dev/null +++ b/tests/test-pull-basicauth.sh @@ -0,0 +1,55 @@ +#!/bin/bash +# +# Copyright (C) 2017 Colin Walters +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the +# Free Software Foundation, Inc., 59 Temple Place - Suite 330, +# Boston, MA 02111-1307, USA. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +setup_fake_remote_repo1 "archive" "" "--require-basic-auth" + +echo '1..3' + +repopath=${test_tmpdir}/ostree-srv/gnomerepo +cp -a ${repopath} ${repopath}.orig + +cd ${test_tmpdir} +rm repo -rf +ostree_repo_init repo +unauthaddress=$(cat httpd-address) +badauthaddress=$(echo $unauthaddress | sed -e 's,http://,http://foo:bar@,') +goodauthaddress=$(echo $unauthaddress | sed -e 's,http://,http://foouser:barpw@,') +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin-unauth ${unauthaddress}/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin-badauth ${badauthaddress}/ostree/gnomerepo +${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin-goodauth ${goodauthaddress}/ostree/gnomerepo + +if ${CMD_PREFIX} ostree --repo=repo pull origin-unauth main 2>err.txt; then + fatal "Pulled via unauth" +fi +assert_file_has_content err.txt "401" +echo "ok unauth" +rm -f err.txt +if ${CMD_PREFIX} ostree --repo=repo pull origin-badauth main 2>err.txt; then + fatal "Pulled via badauth" +fi +assert_file_has_content err.txt "401" +rm -f err.txt +echo "ok badauth" + +${CMD_PREFIX} ostree --repo=repo pull origin-goodauth main +echo "ok basic auth"