diff options
| author | Jesper Jensen <jesper@jnsn.dev> | 2026-02-07 16:00:46 +0100 |
|---|---|---|
| committer | Jesper Jensen <jesper@jnsn.dev> | 2026-02-07 16:00:46 +0100 |
| commit | 9f2b31f58fa4e3664e7ec1362fbcfc3b7e0dc35e (patch) | |
| tree | a9402167f21dda2add8a28a7e69e77fb7cc2fddf | |
| parent | dc003d2ca7da471021f9bed6ddc481b0a79cd890 (diff) | |
Add support for anonymous auth
We need this to actually run the integration tests. With that said,
please don't run the integration tests unless you need to. It's not nice
to use other peoples infrastructure for tests.
| -rw-r--r-- | src/main.rs | 19 | ||||
| -rw-r--r-- | src/registry.rs | 47 |
2 files changed, 50 insertions, 16 deletions
diff --git a/src/main.rs b/src/main.rs index 4f42d45..0d08fc6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use crate::docker::DockerRef; use crate::manifest::ManifestFile; use crate::dockerfile::DockerfileFile; use crate::db::{Db, SqliteDb}; -use crate::registry::{Registry, HttpRegistry, AuthInfo, basic_auth}; +use crate::registry::{Registry, HttpRegistry, AuthInfo, Credentials, basic_auth}; use rand::distr::{Alphanumeric, SampleString}; use std::ops::Range; @@ -27,6 +27,7 @@ Search FILE for docker images and suggest updates Options: --auth <REGISTRY> <USER> <PASS> Authenticate against REGISTRY (repeatable) +--anonymous-auth <REGISTRY> Access REGISTRY anonymously (repeatable) --config <PATH> Read config from PATH --scratch <DIR> Store temporary files in DIR --metrics-port <PORT> Serve Prometheus metrics on PORT (default: disabled)", @@ -473,7 +474,7 @@ fn main() { if let Some(registry) = it.next() && let Some(username) = it.next() && let Some(password) = it.next() { auths.push(AuthInfo { host: registry.clone(), - auth: basic_auth(username, password), + credentials: Credentials::Basic(basic_auth(username, password)), }); } else { println!("Error: --auth requires three parameters"); @@ -481,6 +482,18 @@ fn main() { std::process::exit(1); } }, + Some("--anonymous-auth") => { + if let Some(registry) = it.next() { + auths.push(AuthInfo { + host: registry.clone(), + credentials: Credentials::Anonymous, + }); + } else { + println!("Error: --anonymous-auth requires a registry parameter"); + help(cmd); + std::process::exit(1); + } + }, Some("--config") => { if let Some(path) = it.next() { config_path = Some(std::path::PathBuf::from(path)); @@ -600,7 +613,7 @@ fn main() { Ok(json_event_parser::JsonEvent::String(v)) => { auths.push(AuthInfo { host: key, - auth: v.into_owned(), + credentials: Credentials::Basic(v.into_owned()), }); }, _ => panic!("Invalid config json"), diff --git a/src/registry.rs b/src/registry.rs index afd2794..9f497fd 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -39,9 +39,14 @@ pub fn basic_auth(user: &str, pass: &str) -> String { return BASE64_STANDARD.encode(format!("{}:{}", user, pass)); } +pub enum Credentials { + Anonymous, + Basic(String), +} + pub struct AuthInfo { pub host: String, - pub auth: String, + pub credentials: Credentials, } enum AuthStage { @@ -92,22 +97,32 @@ impl AuthState { let auth_header = response.headers().get("www-authenticate").unwrap(); match AuthMethod::from_header(auth_header) { Some(AuthMethod::Basic) => { - let basic_auth = format!("Basic {}", self.info.auth); - self.stage = AuthStage::Authorized(basic_auth); - - return Ok(()); + match &self.info.credentials { + Credentials::Basic(creds) => { + self.stage = AuthStage::Authorized(format!("Basic {}", creds)); + return Ok(()); + } + Credentials::Anonymous => { + return Err(format!( + "Server {} requires Basic auth but configured as anonymous", + self.info.host + )); + } + } } Some(AuthMethod::Bearer { realm, scope, service }) => { - let basic_auth = format!("Basic {}", self.info.auth); - let url = format!("{}?service={}&scope={}", realm, service, scope); - let body = ureq::get(url) + let mut request = ureq::get(url) .config() .http_status_as_error(false) - .build() - .header("Authorization", basic_auth) - .call(); + .build(); + + if let Credentials::Basic(creds) = &self.info.credentials { + request = request.header("Authorization", format!("Basic {}", creds)); + } + + let body = request.call(); let body = body .map_err(|x| { @@ -467,7 +482,10 @@ mod tests { #[cfg(feature = "integration")] fn conformance_http_get_tags() { crate::metrics::init(); - let reg = HttpRegistry::new(vec![]); + let reg = HttpRegistry::new(vec![AuthInfo { + host: "registry.hub.docker.com".to_string(), + credentials: Credentials::Anonymous, + }]); test_http_get_tags(®); } @@ -475,7 +493,10 @@ mod tests { #[cfg(feature = "integration")] fn conformance_http_get_digest() { crate::metrics::init(); - let reg = HttpRegistry::new(vec![]); + let reg = HttpRegistry::new(vec![AuthInfo { + host: "registry.hub.docker.com".to_string(), + credentials: Credentials::Anonymous, + }]); test_http_get_digest(®); } } |
