Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/libstore/filetransfer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,9 @@ struct curlFileTransfer : public FileTransfer
curl_easy_setopt(req, CURLOPT_PIPEWAIT, 1);
#endif
#if LIBCURL_VERSION_NUM >= 0x072f00
if (fileTransferSettings.enableHttp2)
// Our writeCallbackWrapper does not support rewinding which breaks
// negotiate/kerberos auth over http/2.
Comment on lines +354 to +355

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Our writeCallbackWrapper does not support rewinding which breaks
// negotiate/kerberos auth over http/2.
// Our writeCallbackWrapper does not support rewinding which breaks
// negotiate/kerberos auth over http/2.
// Curl would need to retry a request, after consuming part of our stream, and we currently don't have
// a way to recover that initial already consumed part.

if (fileTransferSettings.enableHttp2 && request.authmethod != HttpAuthMethod::NEGOTIATE)
curl_easy_setopt(req, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
else
curl_easy_setopt(req, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
Expand Down Expand Up @@ -397,6 +399,14 @@ struct curlFileTransfer : public FileTransfer
curl_easy_setopt(req, CURLOPT_SOCKOPTFUNCTION, cloexec_callback);
#endif

curl_easy_setopt(req, CURLOPT_HTTPAUTH, request.authmethod);
if (request.authmethod == HttpAuthMethod::NEGOTIATE) {
curl_easy_setopt(req, CURLOPT_USERNAME, "");
curl_easy_setopt(req, CURLOPT_PASSWORD, "");
Comment on lines +404 to +405

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
curl_easy_setopt(req, CURLOPT_USERNAME, "");
curl_easy_setopt(req, CURLOPT_PASSWORD, "");
// Initialize the auth stack. It needs to have a username, password to trigger that. Otherwise kerberos isn't going to work.
curl_easy_setopt(req, CURLOPT_USERNAME, "");
curl_easy_setopt(req, CURLOPT_PASSWORD, "");

} else if (request.authmethod == HttpAuthMethod::BEARER) {
curl_easy_setopt(req, CURLOPT_XOAUTH2_BEARER, request.bearer_token.c_str());
}

curl_easy_setopt(req, CURLOPT_CONNECTTIMEOUT, fileTransferSettings.connectTimeout.get());

curl_easy_setopt(req, CURLOPT_LOW_SPEED_LIMIT, 1L);
Expand Down
23 changes: 21 additions & 2 deletions src/libstore/http-binary-cache-store.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ namespace nix {

MakeError(UploadToHTTP, Error);

HttpAuthMethod parseHttpAuthMethod(const std::string &str) {
static const std::map<std::string, HttpAuthMethod> map = {
{"none", HttpAuthMethod::NONE},
{"basic", HttpAuthMethod::BASIC},
{"digest", HttpAuthMethod::DIGEST},
{"negotiate", HttpAuthMethod::NEGOTIATE},
{"ntlm", HttpAuthMethod::NTLM},
{"bearer", HttpAuthMethod::BEARER},
{"any", HttpAuthMethod::ANY},
{"anysafe", HttpAuthMethod::ANYSAFE}};
auto it = map.find(str);
if (it == map.end()) {
throw UsageError("option authmethod has invalid value '%s'", str);
}
return it->second;
}


StringSet HttpBinaryCacheStoreConfig::uriSchemes()
{
Expand Down Expand Up @@ -152,11 +169,13 @@ class HttpBinaryCacheStore :

FileTransferRequest makeRequest(const std::string & path)
{
return FileTransferRequest(
auto request = FileTransferRequest(
hasPrefix(path, "https://") || hasPrefix(path, "http://") || hasPrefix(path, "file://")
? path
: config->cacheUri + "/" + path);

request.authmethod = parseHttpAuthMethod(config->authmethod);
request.bearer_token = config->bearer_token;
return request;
}

void getFile(const std::string & path, Sink & sink) override
Expand Down
4 changes: 4 additions & 0 deletions src/libstore/include/nix/store/filetransfer.hh
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once
///@file

#include "http-binary-cache-store.hh"

#include <string>
#include <future>

Expand Down Expand Up @@ -68,6 +70,8 @@ struct FileTransferRequest
bool verifyTLS = true;
bool head = false;
bool post = false;
HttpAuthMethod authmethod = HttpAuthMethod::BASIC;
std::string bearer_token;
size_t tries = fileTransferSettings.tries;
unsigned int baseRetryTimeMs = RETRY_TIME_MS_DEFAULT;
ActivityId parentAct;
Expand Down
28 changes: 27 additions & 1 deletion src/libstore/include/nix/store/http-binary-cache-store.hh
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
#include "nix/store/binary-cache-store.hh"
#pragma once
///@file

#include "nix/util/types.hh"
#include <curl/curl.h>

#include "binary-cache-store.hh"

namespace nix {

enum struct HttpAuthMethod : unsigned long {
NONE = CURLAUTH_NONE,
BASIC = CURLAUTH_BASIC,
DIGEST = CURLAUTH_DIGEST,
NEGOTIATE = CURLAUTH_NEGOTIATE,
NTLM = CURLAUTH_NTLM,
BEARER = CURLAUTH_BEARER,
ANY = CURLAUTH_ANY,
ANYSAFE = CURLAUTH_ANYSAFE
};

struct HttpBinaryCacheStoreConfig : std::enable_shared_from_this<HttpBinaryCacheStoreConfig>,
virtual Store::Config,
BinaryCacheStoreConfig
Expand All @@ -20,6 +37,15 @@ struct HttpBinaryCacheStoreConfig : std::enable_shared_from_this<HttpBinaryCache

static StringSet uriSchemes();

const Setting<std::string> authmethod{this, "basic", "authmethod",
R"(
libcurl auth method to use (`none`, `basic`, `digest`, `bearer`, `negotiate`, `ntlm`, `any`, or `anysafe`).
See https://curl.se/libcurl/c/CURLOPT_HTTPAUTH.html for more info.
)"};

const Setting<std::string> bearer_token{this, "", "bearer-token",
"Bearer token to use for authentication. Requires `authmethod` to be set to `bearer`."};

static std::string doc();

ref<Store> openStore() const override;
Expand Down
1 change: 1 addition & 0 deletions src/libstore/package.nix
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ mkMesonLibrary (finalAttrs: {
propagatedBuildInputs = [
nix-util
nlohmann_json
curl
];

mesonFlags =
Expand Down
Loading