From d345ca212f44f6ccd998ac3275529481b6f437f4 Mon Sep 17 00:00:00 2001 From: Arlo Siemsen Date: Wed, 6 Sep 2023 14:00:46 -0500 Subject: [PATCH] feat: stabilize credential-process and registry-auth --- Cargo.lock | 2 +- .../cargo-credential-1password/README.md | 17 +- .../cargo-credential-libsecret/README.md | 6 +- .../Cargo.toml | 2 +- .../cargo-credential-macos-keychain/README.md | 7 +- credential/cargo-credential-wincred/README.md | 6 +- credential/cargo-credential/README.md | 2 +- publish.py | 5 + src/bin/cargo/commands/login.rs | 2 +- src/cargo/core/features.rs | 12 +- src/cargo/lib.rs | 4 +- src/cargo/ops/registry/mod.rs | 1 + src/cargo/ops/registry/publish.rs | 1 + src/cargo/sources/registry/download.rs | 1 + src/cargo/sources/registry/http_remote.rs | 14 +- src/cargo/sources/registry/remote.rs | 5 +- src/cargo/util/auth/mod.rs | 53 ++- src/doc/man/cargo-login.md | 25 +- src/doc/man/cargo-logout.md | 12 +- src/doc/man/generated_txt/cargo-login.txt | 26 +- src/doc/man/generated_txt/cargo-logout.txt | 13 +- src/doc/src/SUMMARY.md | 2 + src/doc/src/commands/cargo-login.md | 25 +- src/doc/src/commands/cargo-logout.md | 12 +- src/doc/src/reference/config.md | 71 +++- .../reference/credential-provider-protocol.md | 237 ++++++++++++++ .../src/reference/environment-variables.md | 6 + src/doc/src/reference/registries.md | 6 + .../src/reference/registry-authentication.md | 111 +++++++ src/doc/src/reference/registry-index.md | 17 + src/doc/src/reference/unstable.md | 302 +----------------- src/etc/man/cargo-login.1 | 31 +- src/etc/man/cargo-logout.1 | 12 +- tests/testsuite/cargo_login/help/stdout.log | 2 +- tests/testsuite/credential_process.rs | 115 ++----- tests/testsuite/login.rs | 16 +- tests/testsuite/registry_auth.rs | 22 +- tests/testsuite/search.rs | 6 +- 38 files changed, 712 insertions(+), 497 deletions(-) create mode 100644 src/doc/src/reference/credential-provider-protocol.md create mode 100644 src/doc/src/reference/registry-authentication.md diff --git a/Cargo.lock b/Cargo.lock index fe16465f1d5..97e4595d6bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -368,7 +368,7 @@ dependencies = [ [[package]] name = "cargo-credential-macos-keychain" -version = "0.3.0" +version = "0.3.1" dependencies = [ "cargo-credential", "security-framework", diff --git a/credential/cargo-credential-1password/README.md b/credential/cargo-credential-1password/README.md index 7cc15e05b13..3648efe4bda 100644 --- a/credential/cargo-credential-1password/README.md +++ b/credential/cargo-credential-1password/README.md @@ -1,7 +1,18 @@ # cargo-credential-1password -This is the implementation for the Cargo credential helper for [1password]. -See the [credential-process] documentation for how to use this. +A Cargo [credential provider] for [1password]. + +`cargo-credential-1password` uses the 1password `op` CLI to store the token. You must +install the `op` CLI from the [1password +website](https://1password.com/downloads/command-line/). You must run `op signin` +at least once with the appropriate arguments (such as `op signin my.1password.com user@example.com`), +unless you provide the sign-in-address and email arguments. The master password will be required on each request +unless the appropriate `OP_SESSION` environment variable is set. It supports +the following command-line arguments: +* `--account`: The account shorthand name to use. +* `--vault`: The vault name to use. +* `--sign-in-address`: The sign-in-address, which is a web address such as `my.1password.com`. +* `--email`: The email address to sign in with. [1password]: https://1password.com/ -[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process +[credential provider]: https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html diff --git a/credential/cargo-credential-libsecret/README.md b/credential/cargo-credential-libsecret/README.md index f169323e061..aaba2887f41 100644 --- a/credential/cargo-credential-libsecret/README.md +++ b/credential/cargo-credential-libsecret/README.md @@ -1,7 +1,9 @@ # cargo-credential-libsecret This is the implementation for the Cargo credential helper for [GNOME libsecret]. -See the [credential-process] documentation for how to use this. +See the [credential-provider] documentation for how to use this. + +This credential provider is built-in to cargo as `cargo:libsecret`. [GNOME libsecret]: https://wiki.gnome.org/Projects/Libsecret -[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process +[credential-provider]: https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html diff --git a/credential/cargo-credential-macos-keychain/Cargo.toml b/credential/cargo-credential-macos-keychain/Cargo.toml index 342c771b5e6..172e9c10b6a 100644 --- a/credential/cargo-credential-macos-keychain/Cargo.toml +++ b/credential/cargo-credential-macos-keychain/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-credential-macos-keychain" -version = "0.3.0" +version = "0.3.1" edition.workspace = true license.workspace = true repository = "https://github.com/rust-lang/cargo" diff --git a/credential/cargo-credential-macos-keychain/README.md b/credential/cargo-credential-macos-keychain/README.md index 554116b5572..f5efe496b8f 100644 --- a/credential/cargo-credential-macos-keychain/README.md +++ b/credential/cargo-credential-macos-keychain/README.md @@ -1,7 +1,10 @@ # cargo-credential-macos-keychain This is the implementation for the Cargo credential helper for [macOS Keychain]. -See the [credential-process] documentation for how to use this. +See the [credential-provider] documentation for how to use this. + +This credential provider is built-in to cargo as `cargo:macos-keychain`. [macOS Keychain]: https://support.apple.com/guide/keychain-access/welcome/mac -[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process +[credential-provider]: https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html + diff --git a/credential/cargo-credential-wincred/README.md b/credential/cargo-credential-wincred/README.md index 8c8d1878924..1995e9d76cf 100644 --- a/credential/cargo-credential-wincred/README.md +++ b/credential/cargo-credential-wincred/README.md @@ -1,7 +1,9 @@ # cargo-credential-wincred This is the implementation for the Cargo credential helper for [Windows Credential Manager]. -See the [credential-process] documentation for how to use this. +See the [credential-provider] documentation for how to use this. + +This credential provider is built-in to cargo as `cargo:wincred`. [Windows Credential Manager]: https://support.microsoft.com/en-us/windows/accessing-credential-manager-1b5c916a-6a16-889f-8581-fc16e8165ac0 -[credential-process]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process +[credential-provider]: https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html diff --git a/credential/cargo-credential/README.md b/credential/cargo-credential/README.md index 2311f3e57f5..d87d41bb8c8 100644 --- a/credential/cargo-credential/README.md +++ b/credential/cargo-credential/README.md @@ -5,7 +5,7 @@ provides an interface to store tokens for authorizing access to a registry such as https://crates.io/. Documentation about credential processes may be found at -https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process +https://doc.rust-lang.org/nightly/cargo/reference/credential-provider-protocol.html Example implementations may be found at https://github.com/rust-lang/cargo/tree/master/credential diff --git a/publish.py b/publish.py index 13077a69b86..06993bca20a 100755 --- a/publish.py +++ b/publish.py @@ -17,6 +17,11 @@ TO_PUBLISH = [ + 'credential/cargo-credential', + 'credential/cargo-credential-libsecret', + 'credential/cargo-credential-wincred', + 'credential/cargo-credential-1password', + 'credential/cargo-credential-macos-keychain', 'crates/cargo-platform', 'crates/cargo-util', 'crates/crates-io', diff --git a/src/bin/cargo/commands/login.rs b/src/bin/cargo/commands/login.rs index 262e3d6b05f..2b52f706572 100644 --- a/src/bin/cargo/commands/login.rs +++ b/src/bin/cargo/commands/login.rs @@ -9,7 +9,7 @@ pub fn cli() -> Command { .arg(opt("registry", "Registry to use").value_name("REGISTRY")) .arg( Arg::new("args") - .help("Arguments for the credential provider (unstable)") + .help("Additional arguments for the credential provider") .num_args(0..) .last(true), ) diff --git a/src/cargo/core/features.rs b/src/cargo/core/features.rs index 7a8d007c7e1..d86f3dfc454 100644 --- a/src/cargo/core/features.rs +++ b/src/cargo/core/features.rs @@ -728,7 +728,6 @@ unstable_cli_options!( check_cfg: Option<(/*features:*/ bool, /*well_known_names:*/ bool, /*well_known_values:*/ bool, /*output:*/ bool)> = ("Specify scope of compile-time checking of `cfg` names/values"), codegen_backend: bool = ("Enable the `codegen-backend` option in profiles in .cargo/config.toml file"), config_include: bool = ("Enable the `include` key in config files"), - credential_process: bool = ("Add a config setting to fetch registry authentication tokens by calling an external process"), direct_minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum (direct dependencies only)"), doctest_xcompile: bool = ("Compile and run doctests for non-host target using runner config"), dual_proc_macros: bool = ("Build proc-macros for both the host and the target"), @@ -744,7 +743,6 @@ unstable_cli_options!( panic_abort_tests: bool = ("Enable support to run tests with -Cpanic=abort"), profile_rustflags: bool = ("Enable the `rustflags` option in profiles in .cargo/config.toml file"), publish_timeout: bool = ("Enable the `publish.timeout` key in .cargo/config.toml file"), - registry_auth: bool = ("Authentication for alternative registries"), rustdoc_map: bool = ("Allow passing external documentation mappings to rustdoc"), rustdoc_scrape_examples: bool = ("Allows Rustdoc to scrape code examples from reverse-dependencies"), script: bool = ("Enable support for single-file, `.rs` packages"), @@ -818,6 +816,12 @@ const STABILIZED_TERMINAL_WIDTH: &str = const STABILISED_SPARSE_REGISTRY: &str = "The sparse protocol is now the default for crates.io"; +const STABILIZED_CREDENTIAL_PROCESS: &str = + "Authentication with a credential provider is always available."; + +const STABILIZED_REGISTRY_AUTH: &str = + "Authenticated registries are available if a credential provider is configured."; + fn deserialize_build_std<'de, D>(deserializer: D) -> Result>, D::Error> where D: serde::Deserializer<'de>, @@ -1081,6 +1085,8 @@ impl CliUnstable { "sparse-registry" => stabilized_warn(k, "1.68", STABILISED_SPARSE_REGISTRY), "terminal-width" => stabilized_warn(k, "1.68", STABILIZED_TERMINAL_WIDTH), "doctest-in-workspace" => stabilized_warn(k, "1.72", STABILIZED_DOCTEST_IN_WORKSPACE), + "credential-process" => stabilized_warn(k, "1.74", STABILIZED_CREDENTIAL_PROCESS), + "registry-auth" => stabilized_warn(k, "1.74", STABILIZED_REGISTRY_AUTH), // Unstable features // Sorted alphabetically: @@ -1098,7 +1104,6 @@ impl CliUnstable { } "codegen-backend" => self.codegen_backend = parse_empty(k, v)?, "config-include" => self.config_include = parse_empty(k, v)?, - "credential-process" => self.credential_process = parse_empty(k, v)?, "direct-minimal-versions" => self.direct_minimal_versions = parse_empty(k, v)?, "doctest-xcompile" => self.doctest_xcompile = parse_empty(k, v)?, "dual-proc-macros" => self.dual_proc_macros = parse_empty(k, v)?, @@ -1119,7 +1124,6 @@ impl CliUnstable { "panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?, "profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?, "publish-timeout" => self.publish_timeout = parse_empty(k, v)?, - "registry-auth" => self.registry_auth = parse_empty(k, v)?, "rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?, "rustdoc-scrape-examples" => self.rustdoc_scrape_examples = parse_empty(k, v)?, "separate-nightlies" => self.separate_nightlies = parse_empty(k, v)?, diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index 913c041b6af..d0761295fca 100644 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -78,9 +78,7 @@ //! This is the `#[cargo_test]` proc-macro used by the test suite to define tests. //! - [`credential`](https://github.com/rust-lang/cargo/tree/master/credential) //! This subdirectory contains several packages for implementing the -//! experimental -//! [credential-process](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process) -//! feature. +//! [credential providers](https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html). //! - [`mdman`](https://github.com/rust-lang/cargo/tree/master/crates/mdman) //! ([nightly docs](https://doc.rust-lang.org/nightly/nightly-rustc/mdman/index.html)): //! This is a utility for generating cargo's man pages. See [Building the man diff --git a/src/cargo/ops/registry/mod.rs b/src/cargo/ops/registry/mod.rs index 7d4e99f6bcb..e990d171482 100644 --- a/src/cargo/ops/registry/mod.rs +++ b/src/cargo/ops/registry/mod.rs @@ -145,6 +145,7 @@ fn registry( None, operation, vec![], + false, )?) } else { None diff --git a/src/cargo/ops/registry/publish.rs b/src/cargo/ops/registry/publish.rs index 6e43ca2dbcc..868347287af 100644 --- a/src/cargo/ops/registry/publish.rs +++ b/src/cargo/ops/registry/publish.rs @@ -161,6 +161,7 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> { None, operation, vec![], + false, )?)); } diff --git a/src/cargo/sources/registry/download.rs b/src/cargo/sources/registry/download.rs index 08940b3a1db..9bf838625c1 100644 --- a/src/cargo/sources/registry/download.rs +++ b/src/cargo/sources/registry/download.rs @@ -85,6 +85,7 @@ pub(super) fn download( None, Operation::Read, vec![], + true, )?) } else { None diff --git a/src/cargo/sources/registry/http_remote.rs b/src/cargo/sources/registry/http_remote.rs index 1346b6995ab..9fe76333b19 100644 --- a/src/cargo/sources/registry/http_remote.rs +++ b/src/cargo/sources/registry/http_remote.rs @@ -547,9 +547,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> { return Poll::Ready(Ok(LoadResponse::NotFound)); } StatusCode::Unauthorized - if !self.auth_required - && path == Path::new(RegistryConfig::NAME) - && self.config.cli_unstable().registry_auth => + if !self.auth_required && path == Path::new(RegistryConfig::NAME) => { debug!(target: "network", "re-attempting request for config.json with authorization included."); self.fresh.remove(path); @@ -612,10 +610,6 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> { } } - if !self.config.cli_unstable().registry_auth { - self.auth_required = false; - } - // Looks like we're going to have to do a network request. self.start_fetch()?; @@ -654,6 +648,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> { self.login_url.as_ref(), Operation::Read, self.auth_error_headers.clone(), + true, )?; headers.append(&format!("Authorization: {}", authorization))?; trace!(target: "network", "including authorization for {}", full_url); @@ -724,10 +719,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> { } fn config(&mut self) -> Poll>> { - let mut cfg = ready!(self.config()?).clone(); - if !self.config.cli_unstable().registry_auth { - cfg.auth_required = false; - } + let cfg = ready!(self.config()?).clone(); Poll::Ready(Ok(Some(cfg))) } diff --git a/src/cargo/sources/registry/remote.rs b/src/cargo/sources/registry/remote.rs index 78bf9affc94..d4b5d67103f 100644 --- a/src/cargo/sources/registry/remote.rs +++ b/src/cargo/sources/registry/remote.rs @@ -306,10 +306,7 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> { match ready!(self.load(Path::new(""), Path::new(RegistryConfig::NAME), None)?) { LoadResponse::Data { raw_data, .. } => { trace!("config loaded"); - let mut cfg: RegistryConfig = serde_json::from_slice(&raw_data)?; - if !self.config.cli_unstable().registry_auth { - cfg.auth_required = false; - } + let cfg: RegistryConfig = serde_json::from_slice(&raw_data)?; Poll::Ready(Ok(Some(cfg))) } _ => Poll::Ready(Ok(None)), diff --git a/src/cargo/util/auth/mod.rs b/src/cargo/util/auth/mod.rs index 9f4a3422f95..d60a0624f7f 100644 --- a/src/cargo/util/auth/mod.rs +++ b/src/cargo/util/auth/mod.rs @@ -77,6 +77,7 @@ impl RegistryConfigExtended { fn credential_provider( config: &Config, sid: &SourceId, + require_cred_provider_config: bool, show_warnings: bool, ) -> CargoResult>> { let warn = |message: String| { @@ -88,7 +89,9 @@ fn credential_provider( }; let cfg = registry_credential_config_raw(config, sid)?; + let mut global_provider_defined = true; let default_providers = || { + global_provider_defined = false; if config.cli_unstable().asymmetric_token { // Enable the PASETO provider vec![ @@ -101,7 +104,7 @@ fn credential_provider( }; let global_providers = config .get::>>>("registry.global-credential-providers")? - .filter(|p| !p.is_empty() && config.cli_unstable().credential_process) + .filter(|p| !p.is_empty()) .map(|p| { p.iter() .rev() @@ -112,14 +115,14 @@ fn credential_provider( .unwrap_or_else(default_providers); tracing::debug!(?global_providers); - let providers = match cfg { + match cfg { // If there's a specific provider configured for this registry, use it. Some(RegistryConfig { credential_provider: Some(provider), token, secret_key, .. - }) if config.cli_unstable().credential_process => { + }) => { let provider = resolve_credential_alias(config, provider); if let Some(token) = token { if provider[0] != "cargo:token" { @@ -139,7 +142,7 @@ fn credential_provider( ))?; } } - vec![provider] + return Ok(vec![provider]); } // Warning for both `token` and `secret-key`, stating which will be ignored @@ -173,7 +176,6 @@ fn credential_provider( // One or both of the below individual warnings will trigger } } - global_providers } // Check if a `token` is configured that will be ignored. @@ -191,7 +193,6 @@ fn credential_provider( token.definition ))?; } - global_providers } // Check if a asymmetric token is configured that will be ignored. @@ -210,13 +211,18 @@ fn credential_provider( token.definition ))?; } - global_providers } // If we couldn't find a registry-specific provider, use the fallback provider list. - None | Some(RegistryConfig { .. }) => global_providers, + None | Some(RegistryConfig { .. }) => {} }; - Ok(providers) + if !global_provider_defined && require_cred_provider_config { + bail!( + "authenticated registries require a credential-provider to be configured\n\ + see https://doc.rust-lang.org/cargo/reference/registry-authentication.html for details" + ); + } + Ok(global_providers) } /// Get the credential configuration for a `SourceId`. @@ -402,7 +408,7 @@ impl AuthorizationError { // Only display the _TOKEN environment variable suggestion if the `cargo:token` credential // provider is available for the source. Otherwise setting the environment variable will // have no effect. - let display_token_env_help = credential_provider(config, &sid, false)? + let display_token_env_help = credential_provider(config, &sid, false, false)? .iter() .any(|p| p.first().map(String::as_str) == Some("cargo:token")); Ok(AuthorizationError { @@ -496,6 +502,7 @@ fn credential_action( action: Action<'_>, headers: Vec, args: &[&str], + require_cred_provider_config: bool, ) -> CargoResult { let name = if sid.is_crates_io() { Some(CRATES_IO_REGISTRY) @@ -507,7 +514,7 @@ fn credential_action( name, headers, }; - let providers = credential_provider(config, sid, true)?; + let providers = credential_provider(config, sid, require_cred_provider_config, true)?; let mut any_not_found = false; for provider in providers { let args: Vec<&str> = provider @@ -570,8 +577,15 @@ pub fn auth_token( login_url: Option<&Url>, operation: Operation<'_>, headers: Vec, + require_cred_provider_config: bool, ) -> CargoResult { - match auth_token_optional(config, sid, operation, headers)? { + match auth_token_optional( + config, + sid, + operation, + headers, + require_cred_provider_config, + )? { Some(token) => Ok(token.expose()), None => Err(AuthorizationError::new( config, @@ -589,6 +603,7 @@ fn auth_token_optional( sid: &SourceId, operation: Operation<'_>, headers: Vec, + require_cred_provider_config: bool, ) -> CargoResult>> { tracing::trace!("token requested for {}", sid.display_registry_name()); let mut cache = config.credential_cache(); @@ -609,7 +624,14 @@ fn auth_token_optional( } } - let credential_response = credential_action(config, sid, Action::Get(operation), headers, &[]); + let credential_response = credential_action( + config, + sid, + Action::Get(operation), + headers, + &[], + require_cred_provider_config, + ); if let Some(e) = credential_response.as_ref().err() { if let Some(e) = e.downcast_ref::() { if matches!(e, cargo_credential::Error::NotFound) { @@ -648,7 +670,7 @@ fn auth_token_optional( /// Log out from the given registry. pub fn logout(config: &Config, sid: &SourceId) -> CargoResult<()> { - let credential_response = credential_action(config, sid, Action::Logout, vec![], &[]); + let credential_response = credential_action(config, sid, Action::Logout, vec![], &[], false); if let Some(e) = credential_response.as_ref().err() { if let Some(e) = e.downcast_ref::() { if matches!(e, cargo_credential::Error::NotFound) { @@ -677,7 +699,8 @@ pub fn login( options: LoginOptions<'_>, args: &[&str], ) -> CargoResult<()> { - let credential_response = credential_action(config, sid, Action::Login(options), vec![], args)?; + let credential_response = + credential_action(config, sid, Action::Login(options), vec![], args, false)?; let CredentialResponse::Login = credential_response else { bail!("credential provider produced unexpected response for `login` request: {credential_response:?}") }; diff --git a/src/doc/man/cargo-login.md b/src/doc/man/cargo-login.md index 54c823d2d8d..197636da8df 100644 --- a/src/doc/man/cargo-login.md +++ b/src/doc/man/cargo-login.md @@ -2,18 +2,25 @@ ## NAME -cargo-login --- Save an API token from the registry locally +cargo-login --- Log in to a registry ## SYNOPSIS -`cargo login` [_options_] [_token_] +`cargo login` [_options_] [_token_] -- [_args_] ## DESCRIPTION -This command will save the API token to disk so that commands that require -authentication, such as {{man "cargo-publish" 1}}, will be automatically -authenticated. The token is saved in `$CARGO_HOME/credentials.toml`. `CARGO_HOME` -defaults to `.cargo` in your home directory. +This command will run a credential provider to save a token so that commands +that require authentication, such as {{man "cargo-publish" 1}}, will be +automatically authenticated. + +For the default `cargo:token` credential provider, the token is saved +in `$CARGO_HOME/credentials.toml`. `CARGO_HOME` defaults to `.cargo` +in your home directory. + +If a registry has a credential-provider specified, it will be used. Otherwise, +the providers from the config value `registry.global-credential-providers` will +be attempted, starting from the end of the list. If the _token_ argument is not specified, it will be read from stdin. @@ -43,9 +50,13 @@ Take care to keep the token secret, it should not be shared with anyone else. ## EXAMPLES -1. Save the API token to disk: +1. Save the token for the default registry: cargo login +2. Save the token for a specific registry: + + cargo login --registry my-registry + ## SEE ALSO {{man "cargo" 1}}, {{man "cargo-logout" 1}}, {{man "cargo-publish" 1}} diff --git a/src/doc/man/cargo-logout.md b/src/doc/man/cargo-logout.md index f9c0db58cd6..d8277bf54dc 100644 --- a/src/doc/man/cargo-logout.md +++ b/src/doc/man/cargo-logout.md @@ -10,9 +10,15 @@ cargo-logout --- Remove an API token from the registry locally ## DESCRIPTION -This command will remove the API token from the local credential storage. -Credentials are stored in `$CARGO_HOME/credentials.toml` where `$CARGO_HOME` -defaults to `.cargo` in your home directory. +This command will run a credential provider to remove a saved token. + +For the default `cargo:token` credential provider, credentials are stored +in `$CARGO_HOME/credentials.toml` where `$CARGO_HOME` defaults to `.cargo` +in your home directory. + +If a registry has a credential-provider specified, it will be used. Otherwise, +the providers from the config value `registry.global-credential-providers` will +be attempted, starting from the end of the list. If `--registry` is not specified, then the credentials for the default registry will be removed (configured by diff --git a/src/doc/man/generated_txt/cargo-login.txt b/src/doc/man/generated_txt/cargo-login.txt index cce8efcfbdd..ae8127fc9d9 100644 --- a/src/doc/man/generated_txt/cargo-login.txt +++ b/src/doc/man/generated_txt/cargo-login.txt @@ -1,16 +1,24 @@ CARGO-LOGIN(1) NAME - cargo-login — Save an API token from the registry locally + cargo-login — Log in to a registry SYNOPSIS - cargo login [options] [token] + cargo login [options] [token] – [args] DESCRIPTION - This command will save the API token to disk so that commands that - require authentication, such as cargo-publish(1), will be automatically - authenticated. The token is saved in $CARGO_HOME/credentials.toml. - CARGO_HOME defaults to .cargo in your home directory. + This command will run a credential provider to save a token so that + commands that require authentication, such as cargo-publish(1), will be + automatically authenticated. + + For the default cargo:token credential provider, the token is saved in + $CARGO_HOME/credentials.toml. CARGO_HOME defaults to .cargo in your home + directory. + + If a registry has a credential-provider specified, it will be used. + Otherwise, the providers from the config value + registry.global-credential-providers will be attempted, starting from + the end of the list. If the token argument is not specified, it will be read from stdin. @@ -102,10 +110,14 @@ EXIT STATUS o 101: Cargo failed to complete. EXAMPLES - 1. Save the API token to disk: + 1. Save the token for the default registry: cargo login + 2. Save the token for a specific registry: + + cargo login --registry my-registry + SEE ALSO cargo(1), cargo-logout(1), cargo-publish(1) diff --git a/src/doc/man/generated_txt/cargo-logout.txt b/src/doc/man/generated_txt/cargo-logout.txt index db21a39b4d6..73e50d9a40f 100644 --- a/src/doc/man/generated_txt/cargo-logout.txt +++ b/src/doc/man/generated_txt/cargo-logout.txt @@ -7,9 +7,16 @@ SYNOPSIS cargo logout [options] DESCRIPTION - This command will remove the API token from the local credential - storage. Credentials are stored in $CARGO_HOME/credentials.toml where - $CARGO_HOME defaults to .cargo in your home directory. + This command will run a credential provider to remove a saved token. + + For the default cargo:token credential provider, credentials are stored + in $CARGO_HOME/credentials.toml where $CARGO_HOME defaults to .cargo in + your home directory. + + If a registry has a credential-provider specified, it will be used. + Otherwise, the providers from the config value + registry.global-credential-providers will be attempted, starting from + the end of the list. If --registry is not specified, then the credentials for the default registry will be removed (configured by registry.default diff --git a/src/doc/src/SUMMARY.md b/src/doc/src/SUMMARY.md index 27393655985..9ebd7915bb9 100644 --- a/src/doc/src/SUMMARY.md +++ b/src/doc/src/SUMMARY.md @@ -36,6 +36,8 @@ * [Source Replacement](reference/source-replacement.md) * [External Tools](reference/external-tools.md) * [Registries](reference/registries.md) + * [Registry Authentication](reference/registry-authentication.md) + * [Credential Provider Protocol](reference/credential-provider-protocol.md) * [Running a Registry](reference/running-a-registry.md) * [Registry Index](reference/registry-index.md) * [Registry Web API](reference/registry-web-api.md) diff --git a/src/doc/src/commands/cargo-login.md b/src/doc/src/commands/cargo-login.md index e738dca0626..e2efcfe4fed 100644 --- a/src/doc/src/commands/cargo-login.md +++ b/src/doc/src/commands/cargo-login.md @@ -2,18 +2,25 @@ ## NAME -cargo-login --- Save an API token from the registry locally +cargo-login --- Log in to a registry ## SYNOPSIS -`cargo login` [_options_] [_token_] +`cargo login` [_options_] [_token_] -- [_args_] ## DESCRIPTION -This command will save the API token to disk so that commands that require -authentication, such as [cargo-publish(1)](cargo-publish.html), will be automatically -authenticated. The token is saved in `$CARGO_HOME/credentials.toml`. `CARGO_HOME` -defaults to `.cargo` in your home directory. +This command will run a credential provider to save a token so that commands +that require authentication, such as [cargo-publish(1)](cargo-publish.html), will be +automatically authenticated. + +For the default `cargo:token` credential provider, the token is saved +in `$CARGO_HOME/credentials.toml`. `CARGO_HOME` defaults to `.cargo` +in your home directory. + +If a registry has a credential-provider specified, it will be used. Otherwise, +the providers from the config value `registry.global-credential-providers` will +be attempted, starting from the end of the list. If the _token_ argument is not specified, it will be read from stdin. @@ -122,9 +129,13 @@ details on environment variables that Cargo reads. ## EXAMPLES -1. Save the API token to disk: +1. Save the token for the default registry: cargo login +2. Save the token for a specific registry: + + cargo login --registry my-registry + ## SEE ALSO [cargo(1)](cargo.html), [cargo-logout(1)](cargo-logout.html), [cargo-publish(1)](cargo-publish.html) diff --git a/src/doc/src/commands/cargo-logout.md b/src/doc/src/commands/cargo-logout.md index 16e393b0219..3cc50f6e929 100644 --- a/src/doc/src/commands/cargo-logout.md +++ b/src/doc/src/commands/cargo-logout.md @@ -10,9 +10,15 @@ cargo-logout --- Remove an API token from the registry locally ## DESCRIPTION -This command will remove the API token from the local credential storage. -Credentials are stored in `$CARGO_HOME/credentials.toml` where `$CARGO_HOME` -defaults to `.cargo` in your home directory. +This command will run a credential provider to remove a saved token. + +For the default `cargo:token` credential provider, credentials are stored +in `$CARGO_HOME/credentials.toml` where `$CARGO_HOME` defaults to `.cargo` +in your home directory. + +If a registry has a credential-provider specified, it will be used. Otherwise, +the providers from the config value `registry.global-credential-providers` will +be attempted, starting from the end of the list. If `--registry` is not specified, then the credentials for the default registry will be removed (configured by diff --git a/src/doc/src/reference/config.md b/src/doc/src/reference/config.md index 6d0dba29c91..6a479b81bcd 100644 --- a/src/doc/src/reference/config.md +++ b/src/doc/src/reference/config.md @@ -298,7 +298,9 @@ Cargo will search `PATH` for its executable. Configuration values with sensitive information are stored in the `$CARGO_HOME/credentials.toml` file. This file is automatically created and updated -by [`cargo login`] and [`cargo logout`]. It follows the same format as Cargo config files. +by [`cargo login`] and [`cargo logout`] when using the `cargo:token` credential provider. + +It follows the same format as Cargo config files. ```toml [registry] @@ -537,6 +539,26 @@ directory. This option is deprecated and unused. Cargo always has pipelining enabled. +### `[credential-alias]` +* Type: string or array of strings +* Default: empty +* Environment: `CARGO_CREDENTIAL_ALIAS_` + +The `[credential-alias]` table defines credential provider aliases. +These aliases can be referenced as an element of the `registry.global-credential-providers` +array, or as a credential provider for a specific registry +under `registries..credential-provider`. + +If specified as a string, the value will be split on spaces into path and arguments. + +For example, to define an alias called `my-alias`: + +```toml +[credential-alias] +my-alias = ["/usr/bin/cargo-credential-example", "--argument", "value", "--flag"] +``` +See [Registry Authentication](registry-authentication.md) for more information. + ### `[doc]` The `[doc]` table defines options for the [`cargo doc`] command. @@ -947,6 +969,22 @@ commands like [`cargo publish`] that require authentication. Can be overridden with the `--token` command-line option. +#### `registries..credential-provider` +* Type: string or array of path and arguments +* Default: none +* Environment: `CARGO_REGISTRIES__CREDENTIAL_PROVIDER` + +Specifies the credential provider for the given registry. If not set, the +providers in [`registry.global-credential-providers`](#registryglobal-credential-providers) +will be used. + +If specified as a string, path and arguments will be split on spaces. For +paths or arguments that contain spaces, use an array. + +If the value exists in the [`[credential-alias]`](#credential-alias) table, the alias will be used. + +See [Registry Authentication](registry-authentication.md) for more information. + #### `registries.crates-io.protocol` * Type: string * Default: `sparse` @@ -980,6 +1018,22 @@ by default for registry commands like [`cargo publish`]. Can be overridden with the `--registry` command-line option. +#### `registry.credential-provider` +* Type: string or array of path and arguments +* Default: none +* Environment: `CARGO_REGISTRY_CREDENTIAL_PROVIDER` + +Specifies the credential provider for [crates.io]. If not set, the +providers in [`registry.global-credential-providers`](#registryglobal-credential-providers) +will be used. + +If specified as a string, path and arguments will be split on spaces. For +paths or arguments that contain spaces, use an array. + +If the value exists in the `[credential-alias]` table, the alias will be used. + +See [Registry Authentication](registry-authentication.md) for more information. + #### `registry.token` * Type: string * Default: none @@ -991,6 +1045,21 @@ commands like [`cargo publish`] that require authentication. Can be overridden with the `--token` command-line option. +#### `registry.global-credential-providers` +* Type: array +* Default: `["cargo:token"]` +* Environment: `CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS` + +Specifies the list of global credential providers. If credential provider is not set +for a specific registry using `registries..credential-provider`, Cargo will use +the credential providers in this list. Providers toward the end of the list have precedence. + +Path and arguments are split on spaces. If the path or arguments contains spaces, the credential +provider should be defined in the [`[credential-alias]`](#credential-alias) table and +referenced here by its alias. + +See [Registry Authentication](registry-authentication.md) for more information. + ### `[source]` The `[source]` table defines the registry sources available. See [Source diff --git a/src/doc/src/reference/credential-provider-protocol.md b/src/doc/src/reference/credential-provider-protocol.md new file mode 100644 index 00000000000..b577493ee76 --- /dev/null +++ b/src/doc/src/reference/credential-provider-protocol.md @@ -0,0 +1,237 @@ +# Credential Provider Protocol +This document describes information for building a Cargo credential provider. For information on +setting up or using a credential provider, see [Registry Authentication](registry-authentication.md). + +When using an external credential provider, Cargo communicates with the credential +provider using stdin/stdout messages passed as single lines of JSON. + +Cargo will always execute the credential provider with the `--cargo-plugin` argument. +This enables a credential provider executable to have additional functionality beyond +what Cargo needs. Additional arguments are included in the JSON via the `args` field. + +## JSON messages +The JSON messages in this document have newlines added for readability. +Actual messages must not contain newlines. + +### Credential hello +* Sent by: credential provider +* Purpose: used to identify the supported protocols on process startup +```javascript +{ + "v":[1] +} +``` + +Requests sent by Cargo will include a `v` field set to one of the versions listed here. +If Cargo does not support any of the versions offered by the credential provider, it will issue an +error and shut down the credential process. + +### Registry information +* Sent by: Cargo +Not a message by itself. Included in all messages sent by Cargo as the `registry` field. +```javascript +{ + // Index URL of the registry + "index-url":"https://github.com/rust-lang/crates.io-index", + // Name of the registry in configuration (optional) + "name": "crates-io", + // HTTP headers received from attempting to access an authenticated registry (optional) + "headers": ["WWW-Authenticate: cargo"] +} +``` + +### Login request +* Sent by: Cargo +* Purpose: collect and store credentials +```javascript +{ + // Protocol version + "v":1, + // Action to perform: login + "kind":"login", + // Registry information (see Registry information) + "registry":{"index-url":"sparse+https://registry-url/index/", "name": "my-registry"}, + // User-specified token from stdin or command line (optional) + "token": "", + // URL that the user could visit to get a token (optional) + "login-url": "http://registry-url/login", + // Additional command-line args (optional) + "args":[] +} +``` + +If the `token` field is set, than the credential provider should use the token provided. If +the `token` is not set, then the credential provider should prompt the user for a token. + +In addition to the arguments that may be passed to the credential provider in +configuration, `cargo login` also supports passing additional command line args +via `cargo login -- `. These additional arguments will be included +in the `args` field after any args from Cargo configuration. + +### Read request +* Sent by: Cargo +* Purpose: Get the credential for reading crate information +```javascript +{ + // Protocol version + "v":1, + // Request kind: get credentials + "kind":"get", + // Action to perform: read crate information + "operation":"read", + // Registry information (see Registry information) + "registry":{"index-url":"sparse+https://registry-url/index/", "name": "my-registry"}, + // Additional command-line args (optional) + "args":[] +} +``` + +### Publish request +* Sent by: Cargo +* Purpose: Get the credential for publishing a crate +```javascript +{ + // Protocol version + "v":1, + // Request kind: get credentials + "kind":"get", + // Action to perform: publish crate + "operation":"publish", + // Crate name + "name":"sample", + // Crate version + "vers":"0.1.0", + // Crate checksum + "cksum":"...", + // Registry information (see Registry information) + "registry":{"index-url":"sparse+https://registry-url/index/", "name": "my-registry"}, + // Additional command-line args (optional) + "args":[] +} +``` + +### Get success response +* Sent by: credential provider +* Purpose: Gives the credential to Cargo +```javascript +{"Ok":{ + // Response kind: this was a get request + "kind":"get", + // Token to send to the registry + "token":"...", + // Cache control. Can be one of the following: + // * "never": do not cache + // * "session": cache for the current cargo session + // * "expires": cache for the current cargo session until expiration + "cache":"expires", + // Unix timestamp (only for "cache": "expires") + "expiration":1693942857, + // Is the token operation independent? + "operation_independent":true +}} +``` + +The `token` will be sent to the registry as the value of the `Authorization` HTTP header. + +`operation_independent` indicates whether the token can be cached across different +operations (such as publishing or fetching). In general this should be `true` unless +the provider wants to generate tokens that are scoped to specific operations. + +### Login success response +* Sent by: credential provider +* Purpose: Indicates the login was successful +```javascript +{"Ok":{ + // Response kind: this was a login request + "kind":"login" +}} +``` + +### Logout success response +* Sent by: credential provider +* Purpose: Indicates the logout was successful +```javascript +{"Ok":{ + // Response kind: this was a logout request + "kind":"logout" +}} +``` + +### Failure response (URL not supported) +* Sent by: credential provider +* Purpose: Gives error information to Cargo +```javascript +{"Err":{ + "kind":"url-not-supported" +}} +``` +Sent if the credential provider is designed +to only handle specific registry URLs, and the given URL +is not supported. Cargo will attempt another provider if +available. + +### Failure response (not found) +* Sent by: credential provider +* Purpose: Gives error information to Cargo +```javascript +{"Err":{ + // Error: The credential could not be found in the provider. + "kind":"not-found" +}} +``` +Sent if the credential could not be found. This is expected for +`get` requests where the credential is not available, or `logout` +requests where there is nothing found to erase. + +### Failure response (operation not supported) +* Sent by: credential provider +* Purpose: Gives error information to Cargo +```javascript +{"Err":{ + // Error: The credential could not be found in the provider. + "kind":"operation-not-supported" +}} +``` +Sent if the credential provider does not support the requested operation. +If a provider only supports `get` and a `login` is requested, the +provider should respond with this error. + +### Failure response (other) +* Sent by: credential provider +* Purpose: Gives error information to Cargo +```javascript +{"Err":{ + // Error: something else has failed + "kind":"other", + // Error message string to be displayed + "message": "free form string error message", + // Detailed cause chain for the error (optional) + "caused-by": ["cause 1", "cause 2"] +}} +``` + +## Example communication to request a token for reading: +1. Cargo spawns the credential process, capturing stdin and stdout. +2. Credential process sends the Hello message to Cargo + ```javascript + { "v": [1] } + ``` +3. Cargo sends the CredentialRequest message to the credential process (newlines added for readability). + ```javascript + { + "v": 1, + "kind": "get", + "operation": "read", + "registry":{"index-url":"sparse+https://registry-url/index/"} + } + ``` +4. Credential process sends the CredentialResponse to Cargo (newlines added for readability). + ```javascript + { + "token": "...", + "cache": "session", + "operation_independent": true + } + ``` +5. Cargo closes the stdin pipe to the credential provider and it exits. +6. Cargo uses the token for the remainder of the session (until Cargo exits) when interacting with this registry. diff --git a/src/doc/src/reference/environment-variables.md b/src/doc/src/reference/environment-variables.md index 4572fe2ee52..37c788f8dec 100644 --- a/src/doc/src/reference/environment-variables.md +++ b/src/doc/src/reference/environment-variables.md @@ -124,9 +124,12 @@ In summary, the supported environment variables are: * `CARGO_PROFILE__RPATH` --- The rpath linking option, see [`profile..rpath`]. * `CARGO_PROFILE__SPLIT_DEBUGINFO` --- Controls debug file output behavior, see [`profile..split-debuginfo`]. * `CARGO_PROFILE__STRIP` --- Controls stripping of symbols and/or debuginfos, see [`profile..strip`]. +* `CARGO_REGISTRIES__CREDENTIAL_PROVIDER` --- Credential provider for a registry, see [`registries..credential-provider`]. * `CARGO_REGISTRIES__INDEX` --- URL of a registry index, see [`registries..index`]. * `CARGO_REGISTRIES__TOKEN` --- Authentication token of a registry, see [`registries..token`]. +* `CARGO_REGISTRY_CREDENTIAL_PROVIDER` --- Credential provider for [crates.io], see [`registry.credential-provider`]. * `CARGO_REGISTRY_DEFAULT` --- Default registry for the `--registry` flag, see [`registry.default`]. +* `CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS` --- Credential providers for registries that do not have a specific provider defined. See [`registry.global-credential-providers`]. * `CARGO_REGISTRY_TOKEN` --- Authentication token for [crates.io], see [`registry.token`]. * `CARGO_TARGET__LINKER` --- The linker to use, see [`target..linker`]. The triple must be [converted to uppercase and underscores](config.md#environment-variables). * `CARGO_TARGET__RUNNER` --- The executable runner, see [`target..runner`]. @@ -187,9 +190,12 @@ In summary, the supported environment variables are: [`profile..rpath`]: config.md#profilenamerpath [`profile..split-debuginfo`]: config.md#profilenamesplit-debuginfo [`profile..strip`]: config.md#profilenamestrip +[`registries..credential-provider`]: config.md#registriesnamecredential-provider [`registries..index`]: config.md#registriesnameindex [`registries..token`]: config.md#registriesnametoken +[`registry.credential-provider`]: config.md#registrycredential-provider [`registry.default`]: config.md#registrydefault +[`registry.global-credential-providers`]: config.md#registryglobal-credential-providers [`registry.token`]: config.md#registrytoken [`target..linker`]: config.md#targettriplelinker [`target..runner`]: config.md#targettriplerunner diff --git a/src/doc/src/reference/registries.md b/src/doc/src/reference/registries.md index 74c81943579..f0554be980e 100644 --- a/src/doc/src/reference/registries.md +++ b/src/doc/src/reference/registries.md @@ -11,6 +11,10 @@ support publishing new crates directly from Cargo. If you are implementing a registry server, see [Running a Registry] for more details about the protocol between Cargo and a registry. +If you're using a registry that requires authentication, see [Registry Authentication]. +If you are implementing a credential provider, see [Credential Provider Protocol] +for details. + ## Using an Alternate Registry To use a registry other than [crates.io], the name and index URL of the @@ -117,6 +121,8 @@ controlled via the [`registries.crates-io.protocol`] config key. [Source Replacement]: source-replacement.md [Running a Registry]: running-a-registry.md +[Credential Provider Protocol]: credential-provider-protocol.md +[Registry Authentication]: registry-authentication.md [`cargo publish`]: ../commands/cargo-publish.md [`cargo package`]: ../commands/cargo-package.md [`cargo login`]: ../commands/cargo-login.md diff --git a/src/doc/src/reference/registry-authentication.md b/src/doc/src/reference/registry-authentication.md new file mode 100644 index 00000000000..15a96c6e9f6 --- /dev/null +++ b/src/doc/src/reference/registry-authentication.md @@ -0,0 +1,111 @@ +# Registry Authentication +Cargo authenticates to registries with through credential providers. These +credential providers are external executables or built-in providers that Cargo +uses to store and retreive credentials. + +Using alternative registries with authentication *requires* a credential provider to be configured +to avoid unknowningly storing unecrypted credentials on disk. For historical reasons, public +(non-authenticated) registres do not require credential provider configuration and the `cargo:token` +provider is used if no providers are configured. + +Cargo also includes platform-specific providers that use the operating system to securely store +tokens. The `cargo:token` provider is also included which stores credentials in unencrypted plain +text in the [credentials](config.md#credentials) file. + +## Recommended configuration +It's recommended to configure a global credential provider list in `$CARGO_HOME/config.toml` +which defaults to: +* Windows: `%USERPROFILE%\.cargo\config.toml` +* Unix: `~/.cargo/config.toml` + +This recommended configuration uses the operating system provider, with a fallback to `cargo:token` +to look in Cargo's [credentials](config.md#credentials) file or environment variables. + +Some private registries may also recommend a registry-specific credential-provider. Check your +registry's documentation to see if this is the case. + +### macOS configuration +```toml +# ~/.cargo/config.toml +[registry] +global-credential-providers = ["cargo:token", "cargo:macos-keychain"] +``` + +### Linux (libsecret) configuration +```toml +# ~/.cargo/config.toml +[registry] +global-credential-providers = ["cargo:token", "cargo:libsecret"] +``` + +### Windows configuration +```toml +# %USERPROFILE%\.cargo\config.toml +[registry] +global-credential-providers = ["cargo:token", "cargo:wincred"] +``` + +See [`registry.global-credential-providers`](config.md#registryglobal-credential-providers) +for more details. + +## Built-in providers +Cargo includes several built-in credential providers. The available built-in providers +may change in future Cargo releases (though there are currently no plans to do so). + +### `cargo:token` +Uses Cargo's [credentials](config.md#credentials) file to store tokens unencrypted in plain text. +When retreiving tokens, checks the `CARGO_REGISTRIES__TOKEN` environment variable. +If this credential provider is not listed, then the `*_TOKEN` environment variables will not work. + +### `cargo:wincred` +Uses the Windows Credential Manager to store tokens. + +The credentials are stored as `cargo-registry:` in the Credential Manager +under "Windows Credentials". + +### `cargo:macos-keychain` +Uses the macOS Keychain to store tokens. + +The Keychain Access app can be used to view stored tokens. + +### `cargo:libsecret` +Uses [libsecret](https://wiki.gnome.org/Projects/Libsecret) to store tokens. + +On GNOME, credentials can be viewed using [GNOME Keyring](https://wiki.gnome.org/Projects/GnomeKeyring) +applications. + +### `cargo:token-from-stdout ` +Launch a subprocess that returns a token on stdout. Newlines will be trimmed. +* The process inherits the user's stdin and stderr. +* It should exit 0 on success, and nonzero on error. +* [`cargo login`] and [`cargo logout`] are not supported and return an error if used. + +The following environment variables will be provided to the executed command: + +* `CARGO` --- Path to the `cargo` binary executing the command. +* `CARGO_REGISTRY_INDEX_URL` --- The URL of the registry index. +* `CARGO_REGISTRY_NAME_OPT` --- Optional name of the registry. Should not be used as a lookup key. + +Arguments will be passed on to the subcommand. + +[`cargo login`]: ../commands/cargo-login.md +[`cargo logout`]: ../commands/cargo-logout.md + +## Credential plugins +For credential provider plugins that follow Cargo's [credential provider protocol](credential-provider-protocol.md), +the configuration value should be a string with the path to the executable (or the executable name if on the `PATH`). + +For example, to install [cargo-credential-1password](https://crates.io/crates/cargo-credential-1password) +from crates.io do the following: + +Install the provider with `cargo install cargo-credential-1password` + +In the config, add to (or create) `registry.global-credential-providers`: +```toml +[registry] +global-credential-providers = ["cargo:token", "cargo-credential-1password --email you@example.com"] +``` + +The values in `global-credential-providers` are split on spaces to into path and command-line arguments. To +define a global credential provider where the path or arguments contain spaces, use +the [`[credential-alias]` table](config.md#credential-alias). diff --git a/src/doc/src/reference/registry-index.md b/src/doc/src/reference/registry-index.md index 7f331b826c1..67af8d3cd34 100644 --- a/src/doc/src/reference/registry-index.md +++ b/src/doc/src/reference/registry-index.md @@ -35,6 +35,9 @@ The keys are: - `api`: This is the base URL for the web API. This key is optional, but if it is not specified, commands such as [`cargo publish`] will not work. The web API is described below. +- `auth-required`: indicates whether this is a private registry that requires + all operations to be authenticated including API requests, crate downloads + and sparse index updates. ## Download Endpoint @@ -43,6 +46,8 @@ Cargo supports https, http, and file URLs, HTTP redirects, HTTP1 and HTTP2. The exact specifics of TLS support depend on the platform that Cargo is running on, the version of Cargo, and how it was compiled. +If `auth-required: true` is set in `config.json`, the `Authorization` header +will be included with http(s) download requests. ## Index files The rest of the index repository contains one file for each package, where the @@ -274,6 +279,18 @@ The sparse protocol downloads each index file using an individual HTTP request. this results in a large number of small HTTP requests, performance is significantly improved with a server that supports pipelining and HTTP/2. +#### Sparse authentication +Cargo will attempt to fetch the `config.json` file before +fetching any other files. If the server responds with an HTTP 401, then Cargo will assume +that the registry requires authentication and re-attempt the request for `config.json` +with the authentication token included. + +On authentication failure (or a missing authentication token) the server may include a +`www-authenticate` header with a `Cargo login_url=""` challenge to indicate where the user +can go to get a token. + +Registries that require authentication must set `auth-required: true` in `config.json`. + #### Caching Cargo caches the crate metadata files, and captures the `ETag` or `Last-Modified` HTTP header from the server for each entry. When refreshing crate metadata, Cargo diff --git a/src/doc/src/reference/unstable.md b/src/doc/src/reference/unstable.md index 08e48177b49..456cb22f4cf 100644 --- a/src/doc/src/reference/unstable.md +++ b/src/doc/src/reference/unstable.md @@ -101,9 +101,8 @@ For the latest nightly, see the [nightly version] of this page. * [config-include](#config-include) --- Adds the ability for config files to include other files. * [`cargo config`](#cargo-config) --- Adds a new subcommand for viewing config files. * Registries - * [credential-process](#credential-process) --- Adds support for fetching registry tokens from an external authentication program. * [publish-timeout](#publish-timeout) --- Controls the timeout between uploading the crate and being available in the index - * [registry-auth](#registry-auth) --- Adds support for authenticated registries, and generate registry authentication tokens using asymmetric cryptography. + * [asymmetric-token](#asymmetric-token) --- Adds support for authentication tokens using asymmetric cryptography (`cargo:paseto` provider). * Other * [gitoxide](#gitoxide) --- Use `gitoxide` instead of `git2` for a set of operations. * [script](#script) --- Enable support for single-file `.rs` packages. @@ -933,30 +932,6 @@ It requires the `-Zpublish-timeout` command-line options to be set. timeout = 300 # in seconds ``` -## registry-auth -* Tracking Issue: [10474](https://github.com/rust-lang/cargo/issues/10474) -* RFC: [#3139](https://github.com/rust-lang/rfcs/pull/3139) - -Enables Cargo to include the authorization token for API requests, crate downloads -and sparse index updates by adding a configuration option to config.json -in the registry index. - -To use this feature, the registry server must include `"auth-required": true` in -`config.json`, and you must pass the `-Z registry-auth` flag on the Cargo command line. - -When using the sparse protocol, Cargo will attempt to fetch the `config.json` file before -fetching any other files. If the server responds with an HTTP 401, then Cargo will assume -that the registry requires authentication and re-attempt the request for `config.json` -with the authentication token included. - -On authentication failure (or missing authentication token) the server MAY include a -`WWW-Authenticate` header with a `Cargo login_url` challenge to indicate where the user -can go to get a token. - -``` -WWW-Authenticate: Cargo login_url="https://test-registry-login/me -``` - ## asymmetric-token * Tracking Issue: [10519](https://github.com/rust-lang/cargo/issues/10519) * RFC: [#3231](https://github.com/rust-lang/rfcs/pull/3231) @@ -997,267 +972,6 @@ The "footer" (which is part of the signature) will be a JSON string in UTF-8 and PASETO includes the message that was signed, so the server does not have to reconstruct the exact string from the request in order to check the signature. The server does need to check that the signature is valid for the string in the PASETO and that the contents of that string matches the request. If a claim should be expected for the request but is missing in the PASETO then the request must be rejected. -## credential-process -* Tracking Issue: [#8933](https://github.com/rust-lang/cargo/issues/8933) -* RFC: [#2730](https://github.com/rust-lang/rfcs/pull/2730) - -The `credential-process` feature adds a config setting to fetch registry -authentication tokens by calling an external process. - -To use this feature, you must pass the `-Z credential-process` flag on the -command-line. - -### `credential-process` Configuration - -To configure which process to run to fetch the token, specify the process in -the `registry` table in a [config file] with spaces separating arguments. If the -path to the provider or its arguments contain spaces, then it mused be defined in -the `credential-alias` table and referenced instead. - -```toml -[registry] -global-credential-providers = ["/usr/bin/cargo-creds"] -``` - -The provider at the end of the list will be attempted first. This ensures -that when config files are merged, files closer to the project (and ultimatly -environment variables) have precedence. - -In this example, the `my-provider` provider will be attempted first, and if -it cannot provide credentials, then the `cargo:token` provider will be used. - -```toml -[registry] -global-credential-providers = ['cargo:token', 'my-provider'] -``` - -If you want to use a different provider for a specific registry, it can be -specified in the `registries` table: - -```toml -[registries.my-registry] -credential-provider = "/usr/bin/cargo-creds" -``` - -The credential provider for crates.io can be specified as: - -```toml -[registry] -credential-provider = "/usr/bin/cargo-creds" -``` - -The value can be a string with spaces separating arguments or it can be a TOML -array of strings. - -For commonly-used providers, or providers that need to contain spaces in the arguments -or path, the `credential-alias` table can be used. These aliases can be referenced -in `credential-provider` or `global-credential-providers`. - -```toml -[credential-alias] -my-alias = ["/usr/bin/cargo-creds", "--argument"] - -[registry] -global-credential-providers = ["cargo:token", "my-alias"] -``` - -### Built-in providers - -Cargo now includes several built-in credential providers. These providers are -executed within the Cargo process. They are identified with the `cargo:` prefix. - -* `cargo:token` - Uses Cargo's config and `credentials.toml` to store the token (default). -* `cargo:wincred` - Uses the Windows Credential Manager to store the token. -* `cargo:macos-keychain` - Uses the macOS Keychain to store the token. -* `cargo:libsecret` - Uses [libsecret](https://wiki.gnome.org/Projects/Libsecret) to store tokens on Linux systems. -* `cargo:token-from-stdout ` - Launch a subprocess that returns a token - on stdout. Newlines will be trimmed. The process inherits the user's stdin and stderr. - It should exit 0 on success, and nonzero on error. - - With this form, [`cargo login`] and [`cargo logout`] are not supported and - return an error if used. - - The following environment variables will be provided to the executed command: - - * `CARGO` --- Path to the `cargo` binary executing the command. - * `CARGO_REGISTRY_INDEX_URL` --- The URL of the registry index. - * `CARGO_REGISTRY_NAME_OPT` --- Optional name of the registry. Should not be used as a storage key. Not always available. - -* `cargo:paseto` - implements asymmetric token support (RFC3231) as a credential provider. Requires `-Zasymmetric-token`. - - -`cargo-credential-1password` uses the 1password `op` CLI to store the token. You must -install the `op` CLI from the [1password -website](https://1password.com/downloads/command-line/). You must run `op -signin` at least once with the appropriate arguments (such as `op signin -my.1password.com user@example.com`), unless you provide the sign-in-address -and email arguments. The master password will be required on each request -unless the appropriate `OP_SESSION` environment variable is set. It supports -the following command-line arguments: -* `--account`: The account shorthand name to use. -* `--vault`: The vault name to use. -* `--sign-in-address`: The sign-in-address, which is a web address such as `my.1password.com`. -* `--email`: The email address to sign in with. - -Install the provider with `cargo install cargo-credential-1password` -In the config, add it to `global-credential-providers`: -```toml -[registry] -global-credential-providers = ["cargo-credential-1password"] -``` - -### JSON Interface -When using an external credential provider, Cargo communicates with the credential -provider using stdin/stdout messages passed as a single line of JSON. - -Cargo will always execute the credential provider with the `--cargo-plugin` argument. -This enables a credential provider executable to have additional functionality beyond -how Cargo uses it. - -The messages here have additional newlines added for readability. -Actual messages must not contain newlines. - -#### Credential hello -* Sent by: credential provider -* Purpose: used to identify the supported protocols on process startup -```javascript -{ - "v":[1] -} -``` - -#### Login request -* Sent by: Cargo -* Purpose: collect and store credentials -```javascript -{ - // Protocol version - "v":1, - // Action to perform: login - "kind":"login", - // Registry information - "registry":{"index-url":"sparse+https://registry-url/index/", "name": "my-registry"}, -} -``` - -#### Read request -* Sent by: Cargo -* Purpose: Get the credential for reading crate information -```javascript -{ - // Protocol version - "v":1, - // Request kind: get credentials - "kind":"get", - // Action to perform: read crate information - "operation":"read", - // Registry information - "registry":{"index-url":"sparse+https://registry-url/index/", "name": "my-registry"}, - // Additional command-line args (optional) - "args":[] -} -``` - -#### Publish request -* Sent by: Cargo -* Purpose: Get the credential for publishing a crate -```javascript -{ - // Protocol version - "v":1, - // Request kind: get credentials - "kind":"get", - // Action to perform: publish crate - "operation":"publish", - // Crate name - "name":"sample", - // Crate version - "vers":"0.1.0", - // Crate checksum - "cksum":"...", - // Registry information - "registry":{"index-url":"sparse+https://registry-url/index/", "name": "my-registry"}, - // Additional command-line args (optional) - "args":[] -} -``` - -#### Success response -* Sent by: credential process -* Purpose: Gives the credential to Cargo -```javascript -{"Ok":{ - // Response kind: this was a get request kind - "kind":"get", - // Token to send to the registry - "token":"...", - // Cache control. Can be one of the following: - // * "never" - // * "session" - // * "expires" - "cache":"expires", - // Unix timestamp (only for "cache": "expires") - "expiration":1693942857, - // Is the token operation independent? - "operation_independent":true -}} -``` - -#### Failure response -* Sent by: credential process -* Purpose: Gives error information to Cargo -```javascript -{"Err":{ - // Error: the credential provider does not support the - // registry - "kind":"url-not-supported", - - // Error: The credential could not be found in the provider. - // using `cargo login --registry ...`. - "kind":"not-found", - - // Error: something else has failed - "kind":"other", - "detail": "free form string error message" -}} -``` - -#### Example communication to request a token for reading: -1. Cargo spawns the credential process, capturing stdin and stdout. -2. Credential process sends the Hello message to Cargo - ```javascript - { "v": [1] } - ``` -3. Cargo sends the CredentialRequest message to the credential process (newlines added for readability). - ```javascript - { - "v": 1, - "kind": "get", - "operation": "read", - "registry":{"index-url":"sparse+https://registry-url/index/", "name":"ado2"}, - "args":[] - } - ``` -4. Credential process sends the CredentialResponse to Cargo (newlines added for readability). - ```javascript - { - "token": "...", - "cache": "session", - "operation_independent": false - } - ``` -5. Credential process exits -6. Cargo uses the token for the remainder of the session (until Cargo exits) when interacting with this registry. - -[`cargo login`]: ../commands/cargo-login.md -[`cargo logout`]: ../commands/cargo-logout.md -[`cargo publish`]: ../commands/cargo-publish.md -[`cargo owner`]: ../commands/cargo-owner.md -[`cargo yank`]: ../commands/cargo-yank.md -[`credentials.toml` file]: config.md#credentials -[crates.io]: https://crates.io/ -[config file]: config.md - ## `cargo config` * Original Issue: [#2362](https://github.com/rust-lang/cargo/issues/2362) @@ -1779,7 +1493,7 @@ See [Registry Protocols](registries.md#registry-protocols) for more information. The [`cargo logout`] command has been stabilized in the 1.70 release. [target triple]: ../appendix/glossary.md#target '"target" (glossary)' - +[`cargo logout`]: ../commands/cargo-logout.md ## `doctest-in-workspace` @@ -1798,3 +1512,15 @@ in `cargo build` as an example for more details. [`[lints]`](manifest.html#the-lints-section) (enabled via `-Zlints`) has been stabilized in the 1.74 release. +## credential-process + +The `-Z credential-process` feature has been stabilized in the 1.74 release. + +See [Registry Authentication](registry-authentication.md) documentation for details. + +## registry-auth + +The `-Z registry-auth` feature has been stabilized in the 1.74 release with the additional +requirement that a credential-provider is configured. + +See [Registry Authentication](registry-authentication.md) documentation for details. diff --git a/src/etc/man/cargo-login.1 b/src/etc/man/cargo-login.1 index 1ae1cc626ac..92b3b3f3c30 100644 --- a/src/etc/man/cargo-login.1 +++ b/src/etc/man/cargo-login.1 @@ -4,14 +4,21 @@ .ad l .ss \n[.ss] 0 .SH "NAME" -cargo\-login \[em] Save an API token from the registry locally +cargo\-login \[em] Log in to a registry .SH "SYNOPSIS" -\fBcargo login\fR [\fIoptions\fR] [\fItoken\fR] +\fBcargo login\fR [\fIoptions\fR] [\fItoken\fR] \[en] [\fIargs\fR] .SH "DESCRIPTION" -This command will save the API token to disk so that commands that require -authentication, such as \fBcargo\-publish\fR(1), will be automatically -authenticated. The token is saved in \fB$CARGO_HOME/credentials.toml\fR\&. \fBCARGO_HOME\fR -defaults to \fB\&.cargo\fR in your home directory. +This command will run a credential provider to save a token so that commands +that require authentication, such as \fBcargo\-publish\fR(1), will be +automatically authenticated. +.sp +For the default \fBcargo:token\fR credential provider, the token is saved +in \fB$CARGO_HOME/credentials.toml\fR\&. \fBCARGO_HOME\fR defaults to \fB\&.cargo\fR +in your home directory. +.sp +If a registry has a credential\-provider specified, it will be used. Otherwise, +the providers from the config value \fBregistry.global\-credential\-providers\fR will +be attempted, starting from the end of the list. .sp If the \fItoken\fR argument is not specified, it will be read from stdin. .sp @@ -123,7 +130,7 @@ details on environment variables that Cargo reads. .SH "EXAMPLES" .sp .RS 4 -\h'-04' 1.\h'+01'Save the API token to disk: +\h'-04' 1.\h'+01'Save the token for the default registry: .sp .RS 4 .nf @@ -131,5 +138,15 @@ cargo login .fi .RE .RE +.sp +.RS 4 +\h'-04' 2.\h'+01'Save the token for a specific registry: +.sp +.RS 4 +.nf +cargo login \-\-registry my\-registry +.fi +.RE +.RE .SH "SEE ALSO" \fBcargo\fR(1), \fBcargo\-logout\fR(1), \fBcargo\-publish\fR(1) diff --git a/src/etc/man/cargo-logout.1 b/src/etc/man/cargo-logout.1 index 7333cc62c0f..8d73e12a4ef 100644 --- a/src/etc/man/cargo-logout.1 +++ b/src/etc/man/cargo-logout.1 @@ -8,9 +8,15 @@ cargo\-logout \[em] Remove an API token from the registry locally .SH "SYNOPSIS" \fBcargo logout\fR [\fIoptions\fR] .SH "DESCRIPTION" -This command will remove the API token from the local credential storage. -Credentials are stored in \fB$CARGO_HOME/credentials.toml\fR where \fB$CARGO_HOME\fR -defaults to \fB\&.cargo\fR in your home directory. +This command will run a credential provider to remove a saved token. +.sp +For the default \fBcargo:token\fR credential provider, credentials are stored +in \fB$CARGO_HOME/credentials.toml\fR where \fB$CARGO_HOME\fR defaults to \fB\&.cargo\fR +in your home directory. +.sp +If a registry has a credential\-provider specified, it will be used. Otherwise, +the providers from the config value \fBregistry.global\-credential\-providers\fR will +be attempted, starting from the end of the list. .sp If \fB\-\-registry\fR is not specified, then the credentials for the default registry will be removed (configured by diff --git a/tests/testsuite/cargo_login/help/stdout.log b/tests/testsuite/cargo_login/help/stdout.log index faec55c18e7..fd0f3eb3d8f 100644 --- a/tests/testsuite/cargo_login/help/stdout.log +++ b/tests/testsuite/cargo_login/help/stdout.log @@ -4,7 +4,7 @@ Usage: cargo[EXE] login [OPTIONS] [token] [-- [args]...] Arguments: [token] - [args]... Arguments for the credential provider (unstable) + [args]... Additional arguments for the credential provider Options: --registry Registry to use diff --git a/tests/testsuite/credential_process.rs b/tests/testsuite/credential_process.rs index 7c86943ff05..2f59e8856a4 100644 --- a/tests/testsuite/credential_process.rs +++ b/tests/testsuite/credential_process.rs @@ -7,63 +7,6 @@ fn toml_bin(proj: &Project, name: &str) -> String { proj.bin(name).display().to_string().replace('\\', "\\\\") } -#[cargo_test] -fn gated() { - let _alternative = registry::RegistryBuilder::new() - .alternative() - .no_configure_token() - .build(); - - let cratesio = registry::RegistryBuilder::new() - .no_configure_token() - .build(); - - let p = project() - .file( - ".cargo/config", - r#" - [registry] - credential-provider = ["false"] - "#, - ) - .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) - .file("src/lib.rs", "") - .build(); - - p.cargo("publish --no-verify") - .replace_crates_io(cratesio.index_url()) - .masquerade_as_nightly_cargo(&["credential-process"]) - .with_status(101) - .with_stderr( - "\ -[UPDATING] [..] -[ERROR] no token found, please run `cargo login` -or use environment variable CARGO_REGISTRY_TOKEN -", - ) - .run(); - - p.change_file( - ".cargo/config", - r#" - [registry.alternative] - credential-process = "false" - "#, - ); - - p.cargo("publish --no-verify --registry alternative") - .masquerade_as_nightly_cargo(&["credential-process"]) - .with_status(101) - .with_stderr( - "\ -[UPDATING] [..] -[ERROR] no token found for `alternative`, please run `cargo login --registry alternative` -or use environment variable CARGO_REGISTRIES_ALTERNATIVE_TOKEN -", - ) - .run(); -} - /// Setup for a test that will issue a command that needs to fetch a token. /// /// This does the following: @@ -125,8 +68,7 @@ fn publish() { // Checks that credential-process is used for `cargo publish`. let (p, _t) = get_token_test(); - p.cargo("publish --no-verify --registry alternative -Z credential-process -Z registry-auth") - .masquerade_as_nightly_cargo(&["credential-process"]) + p.cargo("publish --no-verify --registry alternative") .with_stderr( r#"[UPDATING] [..] {"v":1,"registry":{"index-url":"[..]","name":"alternative","headers":[..]},"kind":"get","operation":"read"} @@ -151,9 +93,8 @@ fn basic_unsupported() { .credential_provider(&["cargo:token-from-stdout", "false"]) .build(); - cargo_process("login -Z credential-process abcdefg") + cargo_process("login abcdefg") .replace_crates_io(registry.index_url()) - .masquerade_as_nightly_cargo(&["credential-process"]) .with_status(101) .with_stderr( "\ @@ -166,9 +107,8 @@ Caused by: ) .run(); - cargo_process("logout -Z credential-process") + cargo_process("logout") .replace_crates_io(registry.index_url()) - .masquerade_as_nightly_cargo(&["credential-process"]) .with_status(101) .with_stderr( "\ @@ -192,8 +132,7 @@ fn login() { ]) .build(); - cargo_process("login -Z credential-process abcdefg -- cmd3 --cmd4") - .masquerade_as_nightly_cargo(&["credential-process"]) + cargo_process("login abcdefg -- cmd3 --cmd4") .replace_crates_io(registry.index_url()) .with_stderr( r#"[UPDATING] [..] @@ -213,8 +152,7 @@ fn logout() { )]) .build(); - cargo_process("logout -Z credential-process") - .masquerade_as_nightly_cargo(&["credential-process"]) + cargo_process("logout") .replace_crates_io(server.index_url()) .with_stderr( r#"{"v":1,"registry":{"index-url":"https://github.com/rust-lang/crates.io-index","name":"crates-io"},"kind":"logout"} @@ -227,8 +165,7 @@ fn logout() { fn yank() { let (p, _t) = get_token_test(); - p.cargo("yank --version 0.1.0 --registry alternative -Zcredential-process -Zregistry-auth") - .masquerade_as_nightly_cargo(&["credential-process"]) + p.cargo("yank --version 0.1.0 --registry alternative") .with_stderr( r#"[UPDATING] [..] {"v":1,"registry":{"index-url":"[..]","name":"alternative","headers":[..]},"kind":"get","operation":"read"} @@ -243,8 +180,7 @@ fn yank() { fn owner() { let (p, _t) = get_token_test(); - p.cargo("owner --add username --registry alternative -Zcredential-process -Zregistry-auth") - .masquerade_as_nightly_cargo(&["credential-process"]) + p.cargo("owner --add username --registry alternative") .with_stderr( r#"[UPDATING] [..] {"v":1,"registry":{"index-url":"[..]","name":"alternative","headers":[..]},"kind":"get","operation":"read"} @@ -278,8 +214,7 @@ fn invalid_token_output() { .file("src/lib.rs", "") .build(); - p.cargo("publish --no-verify --registry alternative -Z credential-process") - .masquerade_as_nightly_cargo(&["credential-process"]) + p.cargo("publish --no-verify --registry alternative") .with_status(101) .with_stderr( "\ @@ -333,8 +268,7 @@ fn not_found() { .build(); // should not suggest a _TOKEN environment variable since the cargo:token provider isn't available. - cargo_process("install -v foo -Zcredential-process -Zregistry-auth") - .masquerade_as_nightly_cargo(&["credential-process", "registry-auth"]) + cargo_process("install -v foo") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr( @@ -373,8 +307,7 @@ fn all_not_found() { .unwrap(); // should not suggest a _TOKEN environment variable since the cargo:token provider isn't available. - cargo_process("install -v foo -Zcredential-process -Zregistry-auth") - .masquerade_as_nightly_cargo(&["credential-process", "registry-auth"]) + cargo_process("install -v foo") .replace_crates_io(server.index_url()) .with_status(101) .with_stderr( @@ -413,8 +346,7 @@ fn all_not_supported() { ) .unwrap(); - cargo_process("install -v foo -Zcredential-process -Zregistry-auth") - .masquerade_as_nightly_cargo(&["credential-process", "registry-auth"]) + cargo_process("install -v foo") .replace_crates_io(server.index_url()) .with_status(101) .with_stderr( @@ -461,8 +393,7 @@ fn multiple_providers() { ) .unwrap(); - cargo_process("login -Z credential-process -v abcdefg") - .masquerade_as_nightly_cargo(&["credential-process"]) + cargo_process("login -v abcdefg") .replace_crates_io(server.index_url()) .with_stderr( r#"[UPDATING] [..] @@ -481,8 +412,8 @@ fn both_token_and_provider() { .credential_provider(&["cargo:paseto"]) .build(); - cargo_process("login -Z credential-process -Z asymmetric-token") - .masquerade_as_nightly_cargo(&["credential-process", "asymmetric-token"]) + cargo_process("login -Z asymmetric-token") + .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(server.index_url()) .with_stderr( r#"[UPDATING] [..] @@ -508,8 +439,7 @@ fn registry_provider_overrides_global() { ) .unwrap(); - cargo_process("login -Z credential-process -v abcdefg") - .masquerade_as_nightly_cargo(&["credential-process"]) + cargo_process("login -v abcdefg") .env("CARGO_REGISTRY_CREDENTIAL_PROVIDER", "cargo:token") .replace_crates_io(server.index_url()) .with_stderr( @@ -619,8 +549,7 @@ You may press ctrl-c [..] // The output should contain two JSON messages from the provider in boths cases: // The first because the credential is expired, the second because the provider // indicated that the token was non-operation-independent. - p.cargo("publish -Z credential-process --registry alternative --no-verify") - .masquerade_as_nightly_cargo(&["credential-process"]) + p.cargo("publish --registry alternative --no-verify") .with_stderr(output) .run(); @@ -636,8 +565,7 @@ You may press ctrl-c [..] ), ); - p.cargo("publish -Z credential-process --registry alternative --no-verify") - .masquerade_as_nightly_cargo(&["credential-process"]) + p.cargo("publish --registry alternative --no-verify") .with_stderr(output) .run(); } @@ -687,8 +615,7 @@ fn basic_provider() { .build(); Package::new("bar", "0.0.1").alternative(true).publish(); - p.cargo("check -Z credential-process -Z registry-auth") - .masquerade_as_nightly_cargo(&["credential-process", "registry-auth"]) + p.cargo("check") .with_stderr( "\ [UPDATING] `alternative` index @@ -731,8 +658,7 @@ fn unsupported_version() { .credential_provider(&[&provider]) .build(); - cargo_process("login -Z credential-process abcdefg") - .masquerade_as_nightly_cargo(&["credential-process"]) + cargo_process("login abcdefg") .replace_crates_io(registry.index_url()) .with_status(101) .with_stderr( @@ -764,8 +690,7 @@ fn alias_builtin_warning() { ) .unwrap(); - cargo_process("login -Z credential-process abcdefg") - .masquerade_as_nightly_cargo(&["credential-process"]) + cargo_process("login abcdefg") .replace_crates_io(registry.index_url()) .with_stderr( r#"[UPDATING] [..] diff --git a/tests/testsuite/login.rs b/tests/testsuite/login.rs index 9b84c541e47..0eec734cebb 100644 --- a/tests/testsuite/login.rs +++ b/tests/testsuite/login.rs @@ -197,8 +197,8 @@ fn bad_asymmetric_token_args() { .build(); // These cases are kept brief as the implementation is covered by clap, so this is only smoke testing that we have clap configured correctly. - cargo_process("login -Zcredential-process -Zasymmetric-token -- --key-subject") - .masquerade_as_nightly_cargo(&["credential-process", "asymmetric-token"]) + cargo_process("login -Zasymmetric-token -- --key-subject") + .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(registry.index_url()) .with_stderr_contains( " error: a value is required for '--key-subject ' but none was supplied", @@ -228,8 +228,8 @@ fn login_with_asymmetric_token_and_subject_on_stdin() { .no_configure_token() .build(); let credentials = credentials_toml(); - cargo_process("login -v -Z credential-process -Z asymmetric-token -- --key-subject=foo") - .masquerade_as_nightly_cargo(&["credential-process"]) + cargo_process("login -v -Z asymmetric-token -- --key-subject=foo") + .masquerade_as_nightly_cargo(&["asymmetric-token"]) .replace_crates_io(registry.index_url()) .with_stderr_contains( "\ @@ -286,8 +286,8 @@ fn login_with_asymmetric_token_on_stdin() { .no_configure_token() .build(); let credentials = credentials_toml(); - cargo_process("login -vZ credential-process -Z asymmetric-token --registry alternative") - .masquerade_as_nightly_cargo(&["credential-process", "asymmetric-token"]) + cargo_process("login -v -Z asymmetric-token --registry alternative") + .masquerade_as_nightly_cargo(&["asymmetric-token"]) .with_stderr( "\ [UPDATING] [..] @@ -308,8 +308,8 @@ fn login_with_generate_asymmetric_token() { .no_configure_token() .build(); let credentials = credentials_toml(); - cargo_process("login -Z credential-process -Z asymmetric-token --registry alternative") - .masquerade_as_nightly_cargo(&["credential-process", "asymmetric-token"]) + cargo_process("login -Z asymmetric-token --registry alternative") + .masquerade_as_nightly_cargo(&["asymmetric-token"]) .with_stderr("[UPDATING] `alternative` index\nk3.public.[..]") .run(); let credentials = fs::read_to_string(&credentials).unwrap(); diff --git a/tests/testsuite/registry_auth.rs b/tests/testsuite/registry_auth.rs index 9f127669df3..df2bdf565d7 100644 --- a/tests/testsuite/registry_auth.rs +++ b/tests/testsuite/registry_auth.rs @@ -6,10 +6,12 @@ use cargo_test_support::{project, Execs, Project}; fn cargo(p: &Project, s: &str) -> Execs { let mut e = p.cargo(s); - e.masquerade_as_nightly_cargo(&["registry-auth", "credential-process", "asymmetric-token"]) - .arg("-Zregistry-auth") - .arg("-Zcredential-process") + e.masquerade_as_nightly_cargo(&["asymmetric-token"]) .arg("-Zasymmetric-token"); + e.env( + "CARGO_REGISTRY_GLOBAL_CREDENTIAL_PROVIDERS", + "cargo:paseto cargo:token", + ); e } @@ -44,7 +46,7 @@ static SUCCESS_OUTPUT: &'static str = "\ "; #[cargo_test] -fn requires_nightly() { +fn requires_credential_provider() { let _registry = RegistryBuilder::new() .alternative() .auth_required() @@ -56,14 +58,14 @@ fn requires_nightly() { .with_status(101) .with_stderr( r#"[UPDATING] `alternative` index -[DOWNLOADING] crates ... -error: failed to download from `[..]/dl/bar/0.0.1/download` +error: failed to download `bar v0.0.1 (registry `alternative`)` Caused by: - failed to get successful HTTP response from `[..]` (127.0.0.1), got 401 - body: - Unauthorized message from server. -"#, + unable to get packages from source + +Caused by: + authenticated registries require a credential-provider to be configured + see https://doc.rust-lang.org/cargo/reference/registry-authentication.html for details"#, ) .run(); } diff --git a/tests/testsuite/search.rs b/tests/testsuite/search.rs index dd54a5bcf4b..4c3155c8fb2 100644 --- a/tests/testsuite/search.rs +++ b/tests/testsuite/search.rs @@ -173,8 +173,7 @@ fn colored_results() { fn auth_required_failure() { let server = setup().auth_required().no_configure_token().build(); - cargo_process("-Zregistry-auth search postgres") - .masquerade_as_nightly_cargo(&["registry-auth"]) + cargo_process("search postgres") .replace_crates_io(server.index_url()) .with_status(101) .with_stderr_contains("[ERROR] no token found, please run `cargo login`") @@ -185,8 +184,7 @@ fn auth_required_failure() { fn auth_required() { let server = setup().auth_required().build(); - cargo_process("-Zregistry-auth search postgres") - .masquerade_as_nightly_cargo(&["registry-auth"]) + cargo_process("search postgres") .replace_crates_io(server.index_url()) .with_stdout_contains(SEARCH_RESULTS) .run();