From 7ee90dc71fe17fa933c2edb3a0a94120a99e0df0 Mon Sep 17 00:00:00 2001 From: Zanie Blue Date: Thu, 21 Mar 2024 12:10:43 -0500 Subject: [PATCH] Fix authentication with JFrog artifactories (#2592) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes #2566 We were storing the username e.g. `charlie@astral.sh` as a percent-encoded string `charlie%40astral.sh` which resulted in different headers and broke JFrog's artifactory which apparently does not decode usernames. Tested with a JFrog artifactory and AWS CodeArtifact although it is worth noting that AWS does _not_ have a username with an `@` — it'd be nice to test another artifactory with percent-encoded characters in the username and/or password. --- Cargo.lock | 1 + crates/uv-auth/Cargo.toml | 1 + crates/uv-auth/src/store.rs | 8 +++++++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 815aaa052..c6d076d25 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4424,6 +4424,7 @@ dependencies = [ "tokio", "tracing", "url", + "urlencoding", "wiremock", ] diff --git a/crates/uv-auth/Cargo.toml b/crates/uv-auth/Cargo.toml index 8ed8b1522..0e4851fe1 100644 --- a/crates/uv-auth/Cargo.toml +++ b/crates/uv-auth/Cargo.toml @@ -14,6 +14,7 @@ task-local-extensions = { workspace = true } thiserror = { workspace = true } tracing = { workspace = true } url = { workspace = true } +urlencoding = { workspace = true } once_cell = { workspace = true } [dev-dependencies] diff --git a/crates/uv-auth/src/store.rs b/crates/uv-auth/src/store.rs index d43824f84..9ac85234e 100644 --- a/crates/uv-auth/src/store.rs +++ b/crates/uv-auth/src/store.rs @@ -100,7 +100,13 @@ impl AuthenticationStore { return; } let auth = UrlAuthData { - username: url.username().to_string(), + // Using the encoded username can break authentication when `@` is converted to `%40` + // so we decode it for storage; RFC7617 does not explicitly say that authentication should + // not be percent-encoded, but the omission of percent-encoding from all encoding discussion + // indicates that it probably should not be done. + username: urlencoding::decode(url.username()) + .expect("An encoded username should always decode") + .into_owned(), password: url.password().map(str::to_string), }; credentials.insert(netloc, Some(Credential::UrlEncoded(auth)));