mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-18 14:29:57 +00:00
Fail with specific error message when no password on auth always (#12313)
This addresses a small part of #12280, namely when you have `authenticate` set to `always`, it will output a distinct error message for the case where you have a username but are missing a password.
This commit is contained in:
parent
f7d9b0e2fa
commit
615cd6e045
2 changed files with 55 additions and 7 deletions
|
@ -196,6 +196,7 @@ impl Middleware for AuthMiddleware {
|
||||||
extensions,
|
extensions,
|
||||||
next,
|
next,
|
||||||
&url,
|
&url,
|
||||||
|
auth_policy,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
@ -212,7 +213,9 @@ impl Middleware for AuthMiddleware {
|
||||||
// If it's fully authenticated, finish the request
|
// If it's fully authenticated, finish the request
|
||||||
if credentials.password().is_some() {
|
if credentials.password().is_some() {
|
||||||
trace!("Request for {url} is fully authenticated");
|
trace!("Request for {url} is fully authenticated");
|
||||||
return self.complete_request(None, request, extensions, next).await;
|
return self
|
||||||
|
.complete_request(None, request, extensions, next, auth_policy)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we just found a username, we'll make the request then look for password elsewhere
|
// If we just found a username, we'll make the request then look for password elsewhere
|
||||||
|
@ -286,7 +289,7 @@ impl Middleware for AuthMiddleware {
|
||||||
trace!("Retrying request for {url} with credentials from cache {credentials:?}");
|
trace!("Retrying request for {url} with credentials from cache {credentials:?}");
|
||||||
retry_request = credentials.authenticate(retry_request);
|
retry_request = credentials.authenticate(retry_request);
|
||||||
return self
|
return self
|
||||||
.complete_request(None, retry_request, extensions, next)
|
.complete_request(None, retry_request, extensions, next, auth_policy)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,7 +303,13 @@ impl Middleware for AuthMiddleware {
|
||||||
retry_request = credentials.authenticate(retry_request);
|
retry_request = credentials.authenticate(retry_request);
|
||||||
trace!("Retrying request for {url} with {credentials:?}");
|
trace!("Retrying request for {url} with {credentials:?}");
|
||||||
return self
|
return self
|
||||||
.complete_request(Some(credentials), retry_request, extensions, next)
|
.complete_request(
|
||||||
|
Some(credentials),
|
||||||
|
retry_request,
|
||||||
|
extensions,
|
||||||
|
next,
|
||||||
|
auth_policy,
|
||||||
|
)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +318,7 @@ impl Middleware for AuthMiddleware {
|
||||||
trace!("Retrying request for {url} with username from cache {credentials:?}");
|
trace!("Retrying request for {url} with username from cache {credentials:?}");
|
||||||
retry_request = credentials.authenticate(retry_request);
|
retry_request = credentials.authenticate(retry_request);
|
||||||
return self
|
return self
|
||||||
.complete_request(None, retry_request, extensions, next)
|
.complete_request(None, retry_request, extensions, next, auth_policy)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -334,13 +343,16 @@ impl AuthMiddleware {
|
||||||
request: Request,
|
request: Request,
|
||||||
extensions: &mut Extensions,
|
extensions: &mut Extensions,
|
||||||
next: Next<'_>,
|
next: Next<'_>,
|
||||||
|
auth_policy: AuthPolicy,
|
||||||
) -> reqwest_middleware::Result<Response> {
|
) -> reqwest_middleware::Result<Response> {
|
||||||
let Some(credentials) = credentials else {
|
let Some(credentials) = credentials else {
|
||||||
// Nothing to insert into the cache if we don't have credentials
|
// Nothing to insert into the cache if we don't have credentials
|
||||||
return next.run(request, extensions).await;
|
return next.run(request, extensions).await;
|
||||||
};
|
};
|
||||||
|
|
||||||
let url = request.url().clone();
|
let url = request.url().clone();
|
||||||
|
if matches!(auth_policy, AuthPolicy::Always) && credentials.password().is_none() {
|
||||||
|
return Err(Error::Middleware(format_err!("Missing password for {url}")));
|
||||||
|
}
|
||||||
let result = next.run(request, extensions).await;
|
let result = next.run(request, extensions).await;
|
||||||
|
|
||||||
// Update the cache with new credentials on a successful request
|
// Update the cache with new credentials on a successful request
|
||||||
|
@ -363,6 +375,7 @@ impl AuthMiddleware {
|
||||||
extensions: &mut Extensions,
|
extensions: &mut Extensions,
|
||||||
next: Next<'_>,
|
next: Next<'_>,
|
||||||
url: &str,
|
url: &str,
|
||||||
|
auth_policy: AuthPolicy,
|
||||||
) -> reqwest_middleware::Result<Response> {
|
) -> reqwest_middleware::Result<Response> {
|
||||||
let credentials = Arc::new(credentials);
|
let credentials = Arc::new(credentials);
|
||||||
|
|
||||||
|
@ -370,7 +383,7 @@ impl AuthMiddleware {
|
||||||
if credentials.password().is_some() {
|
if credentials.password().is_some() {
|
||||||
trace!("Request for {url} is already fully authenticated");
|
trace!("Request for {url} is already fully authenticated");
|
||||||
return self
|
return self
|
||||||
.complete_request(Some(credentials), request, extensions, next)
|
.complete_request(Some(credentials), request, extensions, next, auth_policy)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -402,7 +415,7 @@ impl AuthMiddleware {
|
||||||
};
|
};
|
||||||
|
|
||||||
return self
|
return self
|
||||||
.complete_request(credentials, request, extensions, next)
|
.complete_request(credentials, request, extensions, next, auth_policy)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10081,6 +10081,41 @@ fn add_auth_policy_always_without_credentials() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// In authentication "always", authenticated requests with a username but
|
||||||
|
/// no discoverable password will fail.
|
||||||
|
#[test]
|
||||||
|
fn add_auth_policy_always_with_username_no_password() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12");
|
||||||
|
|
||||||
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(indoc! { r#"
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "1.0.0"
|
||||||
|
requires-python = ">=3.11, <4"
|
||||||
|
dependencies = []
|
||||||
|
|
||||||
|
[[tool.uv.index]]
|
||||||
|
name = "my-index"
|
||||||
|
url = "https://public@pypi.org/simple"
|
||||||
|
authenticate = "always"
|
||||||
|
default = true
|
||||||
|
"#
|
||||||
|
})?;
|
||||||
|
|
||||||
|
uv_snapshot!(context.add().arg("anyio"), @r"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: Failed to fetch: `https://pypi.org/simple/anyio/`
|
||||||
|
Caused by: Missing password for https://pypi.org/simple/anyio/
|
||||||
|
"
|
||||||
|
);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// In authentication "never", even if the correct credentials are supplied
|
/// In authentication "never", even if the correct credentials are supplied
|
||||||
/// in the URL, no authenticated requests will be allowed.
|
/// in the URL, no authenticated requests will be allowed.
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue