use axum::body::Body;
use axum::http::{Request, StatusCode, header};
use tower::ServiceExt;
use x509_parser::prelude::FromDer;
mod common;
use common::{EcSigner, FailingSigner, acme, p, test_app, test_app_with_signer};
use std::sync::Arc;
async fn get(app: axum::Router, path: &str) -> axum::response::Response {
app.oneshot(Request::get(path).body(Body::empty()).unwrap())
.await
.unwrap()
}
#[tokio::test]
async fn the_local_cas_certificate_is_served_and_parses() {
let res = get(test_app().await, &p("/ca.pem")).await;
assert_eq!(res.status(), StatusCode::OK);
assert_eq!(
res.headers()
.get(header::CONTENT_TYPE)
.and_then(|v| v.to_str().ok()),
Some("application/x-pem-file"),
);
let pem = String::from_utf8(
axum::body::to_bytes(res.into_body(), usize::MAX)
.await
.unwrap()
.to_vec(),
)
.unwrap();
let der = acme_proxy_core::cert::leaf_der_from_chain(&pem)
.expect("served bytes must parse as a PEM certificate");
let (_, cert) = x509_parser::certificate::X509Certificate::from_der(&der)
.expect("and as a valid X.509 certificate");
let constraints = cert
.basic_constraints()
.expect("basicConstraints must parse")
.expect("a CA certificate carries basicConstraints");
assert!(constraints.value.ca, "the served certificate must be a CA");
}
#[tokio::test]
async fn the_served_anchor_is_the_one_appended_to_an_issued_chain() {
let app = test_app().await;
let signer = EcSigner::new();
let (_account_url, _order_url, chain) =
acme::issue_certificate(&app, &signer, &["example.com"]).await;
let res = get(app, &p("/ca.pem")).await;
let anchor = String::from_utf8(
axum::body::to_bytes(res.into_body(), usize::MAX)
.await
.unwrap()
.to_vec(),
)
.unwrap();
assert!(
chain.ends_with(&anchor),
"the issued chain must end with exactly the bytes /ca.pem serves"
);
assert_ne!(
chain.trim(),
anchor.trim(),
"and must carry a leaf in front of it โ otherwise the assertion above \
passes for an empty anchor"
);
}
#[tokio::test]
async fn a_backend_with_no_anchor_answers_404() {
let (app, _database) = test_app_with_signer(Arc::new(FailingSigner)).await;
let res = get(app, &p("/ca.pem")).await;
assert_eq!(res.status(), StatusCode::NOT_FOUND);
let body = axum::body::to_bytes(res.into_body(), usize::MAX)
.await
.unwrap();
assert!(
body.is_empty(),
"no body at all, rather than something a PEM parser might accept"
);
}