Files
RustProxy/src/acme/providers/tests.rs
T
2026-10-17 11:57:16 +02:00

176 lines
5.4 KiB
Rust

mod challenge_tests {
use super::*;
use axum::{body::Body, Extension};
use http::Request;
use http_body_util::BodyExt;
use tower::ServiceExt;
async fn fixture() -> (Arc<App>, tempfile::TempDir) {
let directory = tempfile::tempdir().unwrap();
let certs = directory.path().join("certs");
crate::tls::initialize_default(&certs).unwrap();
let root = certs.join("acme-http01/.well-known/acme-challenge");
std::fs::create_dir_all(&root).unwrap();
std::fs::write(root.join("sample_token"), b"sample_token.thumbprint").unwrap();
let config = crate::config::Config::default();
let policy = crate::config::ValidationPolicy {
proxy_addr: "127.0.0.1:8080".parse().unwrap(),
admin_addr: "127.0.0.1:9090".parse().unwrap(),
tls_addr: None,
cert_dir: Some(certs),
data_dir: None,
};
let store = crate::db::Store::open(&directory.path().join("db"), &config)
.await
.unwrap();
let auth = crate::auth::Auth::new(store.clone(), directory.path().to_owned())
.await
.unwrap();
let snapshot = crate::config::compile(config, 0, &policy).unwrap();
let app = App::new(
store,
snapshot,
policy,
auth,
8,
Duration::from_secs(2),
Duration::from_secs(2),
Duration::from_secs(30),
);
*app.acme.job.lock().unwrap() = Some(Job {
id: "test".into(),
certificate_id: "test".into(),
status: "running",
kind: "issue",
provider: "http01".into(),
domains: vec!["example.org".into()],
environment: "staging".into(),
message: "test".into(),
log_directory: "test/logs".into(),
certificate: None,
});
(app, directory)
}
#[tokio::test]
async fn http01_serves_only_current_job_tokens_and_correct_head() {
let (app, _directory) = fixture().await;
let router = crate::proxy::router(app.clone());
let req = |method, host, path| {
Request::builder()
.method(method)
.uri(path)
.header("host", host)
.body(Body::empty())
.unwrap()
};
let response = router
.clone()
.oneshot(req(
"GET",
"example.org",
"/.well-known/acme-challenge/sample_token",
))
.await
.unwrap();
assert_eq!(response.status(), 200);
assert_eq!(response.headers()["cache-control"], "no-store");
assert_eq!(
response
.into_body()
.collect()
.await
.unwrap()
.to_bytes()
.as_ref(),
b"sample_token.thumbprint"
);
let response = router
.clone()
.oneshot(req(
"HEAD",
"example.org",
"/.well-known/acme-challenge/sample_token",
))
.await
.unwrap();
assert_eq!(response.status(), 200);
assert_eq!(response.headers()["content-length"], "23");
assert!(response
.into_body()
.collect()
.await
.unwrap()
.to_bytes()
.is_empty());
for path in [
"/.well-known/acme-challenge/../sample_token",
"/.well-known/acme-challenge/sample_token?x=1",
"/.well-known/acme-challenge/%2e%2e",
"/.well-known/acme-challenge/missing",
] {
assert_eq!(
router
.clone()
.oneshot(req("GET", "example.org", path))
.await
.unwrap()
.status(),
404
);
}
assert_eq!(
router
.clone()
.oneshot(req(
"GET",
"unrelated.example.org",
"/.well-known/acme-challenge/sample_token"
))
.await
.unwrap()
.status(),
404
);
assert_eq!(
router
.clone()
.oneshot(req(
"POST",
"example.org",
"/.well-known/acme-challenge/sample_token"
))
.await
.unwrap()
.status(),
405
);
let tls = router
.clone()
.layer(Extension(crate::server::Transport { tls: true }));
assert_eq!(
tls.oneshot(req(
"GET",
"example.org",
"/.well-known/acme-challenge/sample_token"
))
.await
.unwrap()
.status(),
404
);
app.acme.job.lock().unwrap().as_mut().unwrap().status = "ready";
assert_eq!(
router
.oneshot(req(
"GET",
"example.org",
"/.well-known/acme-challenge/sample_token"
))
.await
.unwrap()
.status(),
404
);
app.store.close().await;
}
}