Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxy auth with custom HTTP transport #11433

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
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
3 changes: 3 additions & 0 deletions src/cargo/ops/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,9 @@ pub fn configure_http_handle(config: &Config, handle: &mut Easy) -> CargoResult<
if let Some(proxy) = http_proxy(config)? {
handle.proxy(&proxy)?;
}
handle.proxy_auth(&http.proxy_auth.to_easy())?;
Copy link
Contributor

Choose a reason for hiding this comment

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

If this is CargoHttpProxyAuth::Disable should we avoid calling any of the proxy_ methods?

Copy link
Author

Choose a reason for hiding this comment

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

Not calling handle.proxy_auth is the same as calling it with Auth::new().basic(true) [0,1] (support only basic authentication). The idea with "disable" is to tell curl to not negotiate even if the user has a login/pwd in cargo config file.

We could avoid calling proxy_username and proxy_password but I don't think it would change anything, at least from the official curl docs.

[0] https://curl.se/libcurl/c/CURLOPT_PROXYAUTH.html
[1] https://docs.rs/curl/latest/curl/easy/struct.Easy2.html#method.proxy_auth

handle.proxy_username(http.proxy_username.as_deref().unwrap_or(""))?;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a comment about why these need to be called with empty string (instead of just not calling them)?

Copy link
Author

Choose a reason for hiding this comment

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

The comment is in the commit message [0] (second paragraph). Do you want another one in the code?

[0] e7a5905

handle.proxy_password(http.proxy_password.as_deref().unwrap_or(""))?;
if let Some(cainfo) = &http.cainfo {
let cainfo = cainfo.resolve_path(config);
handle.cainfo(&cainfo)?;
Expand Down
33 changes: 32 additions & 1 deletion src/cargo/util/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ use crate::util::{internal, toml as cargo_toml};
use crate::util::{FileLock, Filesystem, IntoUrl, IntoUrlWithBase, Rustc};
use anyhow::{anyhow, bail, format_err, Context as _};
use cargo_util::paths;
use curl::easy::Easy;
use curl::easy::{Auth, Easy};
use lazycell::LazyCell;
use serde::Deserialize;
use toml_edit::{easy as toml, Item};
Expand Down Expand Up @@ -2215,10 +2215,41 @@ impl Drop for PackageCacheLock<'_> {
}
}

#[derive(Debug, Default, Deserialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub enum CargoHttpProxyAuth {
#[default]
Auto,
Copy link
Contributor

Choose a reason for hiding this comment

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

Does the default of Auto introduce any additional HTTP requests for the non-proxy case?

The curl docs indicate that it might:

If more than one bit is set, libcurl will first query the site to see what authentication methods it supports and then pick the best one you allow it to use. For some methods, this will induce an extra network round-trip

Copy link
Author

Choose a reason for hiding this comment

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

This change focuses on proxy authentication specifically, not authentication to arbitrary HTTP servers. The Auth API is used for both problems, thus this paragraph I think. In the non-proxy case there is no additional request to be made.

This could well send an additional request to a proxy that doesn't need authentication, however I don't think it would make a noticeable difference in performance compared to, e.g. the time it takes to update the registry or download kilobytes of crates (?).

Disable,
Basic,
Digest,
Gss,
Ntlm,
}

impl CargoHttpProxyAuth {
pub fn to_easy(&self) -> Auth {
let mut auth = Auth::new();
match self {
Self::Auto => auth.basic(true).digest(true).gssnegotiate(true).ntlm(true),
Self::Disable => &auth,
Self::Basic => auth.basic(true),
Self::Digest => auth.digest(true),
Self::Gss => auth.gssnegotiate(true),
Self::Ntlm => auth.ntlm(true),
};
auth
}
}

#[derive(Debug, Default, Deserialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub struct CargoHttpConfig {
pub proxy: Option<String>,
#[serde(default)]
pub proxy_auth: CargoHttpProxyAuth,
pub proxy_username: Option<String>,
pub proxy_password: Option<String>,
pub low_speed_limit: Option<u32>,
pub timeout: Option<u64>,
pub cainfo: Option<ConfigRelativePath>,
Expand Down
25 changes: 25 additions & 0 deletions src/doc/src/reference/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ vcs = "none" # VCS to use ('git', 'hg', 'pijul', 'fossil', 'none')
[http]
debug = false # HTTP debugging
proxy = "host:port" # HTTP proxy in libcurl format
proxy-auth = "auto" # HTTP proxy authentication mechanism
proxy-username = "" # HTTP proxy username
proxy-password = "" # HTTP proxy password
ssl-version = "tlsv1.3" # TLS version to use
ssl-version.max = "tlsv1.3" # maximum TLS version
ssl-version.min = "tlsv1.1" # minimum TLS version
Expand Down Expand Up @@ -627,6 +630,28 @@ setting in your global git configuration. If none of those are set, the
`HTTPS_PROXY` or `https_proxy` environment variables set the proxy for HTTPS
requests, and `http_proxy` sets it for HTTP requests.

##### `http.proxy-auth`
* Type: string
* Default: "auto"
* Environment: `CARGO_HTTP_PROXY_AUTH`

Sets a mechanism to authenticate against the proxy.
Possible values are: "auto", "disable", "basic", "digest", "gss" and "ntlm".

##### `http.proxy-username`
* Type: string
* Default: none
* Environment: `CARGO_HTTP_PROXY_USERNAME`

Authenticate against the proxy using the given username.

##### `http.proxy-password`
* Type: string
* Default: none
* Environment: `CARGO_HTTP_PROXY_PASSWORD`

Authenticate against the proxy using the given password.

##### `http.timeout`
* Type: integer
* Default: 30
Expand Down
6 changes: 6 additions & 0 deletions src/doc/src/reference/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ In summary, the supported environment variables are:
* `CARGO_FUTURE_INCOMPAT_REPORT_FREQUENCY` - How often we should generate a future incompat report notification, see [`future-incompat-report.frequency`].
* `CARGO_HTTP_DEBUG` — Enables HTTP debugging, see [`http.debug`].
* `CARGO_HTTP_PROXY` — Enables HTTP proxy, see [`http.proxy`].
* `CARGO_HTTP_PROXY_AUTH` — The proxy authentication mechanism, see [`http.proxy-auth`].
* `CARGO_HTTP_PROXY_USERNAME` — The proxy username, see [`http.proxy-username`].
* `CARGO_HTTP_PROXY_PASSWORD` — The proxy password, see [`http.proxy-password`].
* `CARGO_HTTP_TIMEOUT` — The HTTP timeout, see [`http.timeout`].
* `CARGO_HTTP_CAINFO` — The TLS certificate Certificate Authority file, see [`http.cainfo`].
* `CARGO_HTTP_CHECK_REVOKE` — Disables TLS certificate revocation checks, see [`http.check-revoke`].
Expand Down Expand Up @@ -163,6 +166,9 @@ In summary, the supported environment variables are:
[`future-incompat-report.frequency`]: config.md#future-incompat-reportfrequency
[`http.debug`]: config.md#httpdebug
[`http.proxy`]: config.md#httpproxy
[`http.proxy-auth`]: config.md#httpproxy-auth
[`http.proxy-username`]: config.md#httpproxy-username
[`http.proxy-password`]: config.md#httpproxy-password
[`http.timeout`]: config.md#httptimeout
[`http.cainfo`]: config.md#httpcainfo
[`http.check-revoke`]: config.md#httpcheck-revoke
Expand Down