Skip to content

Commit

Permalink
update examples
Browse files Browse the repository at this point in the history
  • Loading branch information
sunli829 committed Jun 22, 2023
1 parent 68f2a08 commit 2e05b48
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 29 deletions.
8 changes: 4 additions & 4 deletions examples/poem/acme-expanded-http-01/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use poem::{
get, handler,
listener::{
acme::{
issue_cert, new_http01_key_map, seconds_until_expiry, AcmeClient, ChallengeType,
Http01Endpoint, ResolveServerCert, ResolvedCertListener, LETS_ENCRYPT_PRODUCTION,
issue_cert, seconds_until_expiry, AcmeClient, ChallengeType, Http01Endpoint,
Http01TokensMap, ResolveServerCert, ResolvedCertListener, LETS_ENCRYPT_PRODUCTION,
},
Listener, TcpListener,
},
Expand All @@ -35,7 +35,7 @@ async fn main() -> Result<(), std::io::Error> {
AcmeClient::try_new(&LETS_ENCRYPT_PRODUCTION.parse().unwrap(), vec![]).await?;
let cert_resolver = Arc::new(ResolveServerCert::default());
let challenge = ChallengeType::Http01;
let keys_for_http_challenge = new_http01_key_map();
let keys_for_http_challenge = Http01TokensMap::new();

{
let domains = vec!["poem.rs".to_string()];
Expand All @@ -54,7 +54,7 @@ async fn main() -> Result<(), std::io::Error> {
)
.await
{
Ok((_pub_cert_pem, _priv_key_pem, cert)) => cert,
Ok(result) => result.rustls_key,
Err(err) => {
eprintln!("failed to issue certificate: {}", err);
sleep(Duration::from_secs(60 * 5)).await;
Expand Down
9 changes: 4 additions & 5 deletions poem/src/listener/acme/auto_cert.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
use std::{
collections::HashMap,
fmt::{self, Debug, Formatter},
path::PathBuf,
sync::Arc,
};

use http::Uri;
use parking_lot::RwLock;

use crate::listener::acme::{builder::AutoCertBuilder, endpoint::Http01Endpoint, ChallengeType};
use crate::listener::acme::{
builder::AutoCertBuilder, endpoint::Http01Endpoint, ChallengeType, Http01TokensMap,
};

/// ACME configuration
pub struct AutoCert {
pub(crate) directory_url: Uri,
pub(crate) domains: Vec<String>,
pub(crate) contacts: Vec<String>,
pub(crate) challenge_type: ChallengeType,
pub(crate) keys_for_http01: Option<Arc<RwLock<HashMap<String, String>>>>,
pub(crate) keys_for_http01: Option<Http01TokensMap>,
pub(crate) cache_path: Option<PathBuf>,
pub(crate) cache_cert: Option<Vec<u8>>,
pub(crate) cache_key: Option<Vec<u8>>,
Expand Down
7 changes: 5 additions & 2 deletions poem/src/listener/acme/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ impl AcmeClient {
})
}

pub(crate) async fn new_order(&mut self, domains: &[String]) -> IoResult<NewOrderResponse> {
pub(crate) async fn new_order<T: AsRef<str>>(
&mut self,
domains: &[T],
) -> IoResult<NewOrderResponse> {
let kid = match &self.kid {
Some(kid) => kid,
None => {
Expand Down Expand Up @@ -82,7 +85,7 @@ impl AcmeClient {
.iter()
.map(|domain| Identifier {
ty: "dns".to_string(),
value: domain.to_string(),
value: domain.as_ref().to_string(),
})
.collect(),
}),
Expand Down
37 changes: 29 additions & 8 deletions poem/src/listener/acme/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,38 @@ use parking_lot::RwLock;

use crate::{error::NotFoundError, Endpoint, IntoResponse, Request, Response, Result};

/// Create a new http01 challenge key map for use in challenge endpoint
/// and `issue_cert`.
pub fn new_http01_key_map() -> Arc<RwLock<HashMap<String, String>>> {
Arc::new(RwLock::new(HashMap::new()))
/// A tokens storage for http01 challenge
#[derive(Debug, Clone, Default)]
pub struct Http01TokensMap(Arc<RwLock<HashMap<String, String>>>);

impl Http01TokensMap {
/// Create a new http01 challenge tokens storage for use in challenge endpoint
/// and [`issue_cert`].
#[inline]
pub fn new() -> Self {
Self::default()
}

/// Inserts an entry to the storage
pub fn insert(&self, token: impl Into<String>, authorization: impl Into<String>) {
self.0.write().insert(token.into(), authorization.into());
}

/// Removes an entry from the storage
pub fn remove(&self, token: impl AsRef<str>) {
self.0.write().remove(token.as_ref());
}

/// Gets the authorization by token
pub fn get(&self, token: impl AsRef<str>) -> Option<String> {
self.0.read().get(token.as_ref()).cloned()
}
}

/// An endpoint for `HTTP-01` challenge.
pub struct Http01Endpoint {
/// Challenge keys for http01 domain verification.
pub keys: Arc<RwLock<HashMap<String, String>>>,
pub keys: Http01TokensMap,
}

#[async_trait::async_trait]
Expand All @@ -26,9 +48,8 @@ impl Endpoint for Http01Endpoint {
.path()
.strip_prefix("/.well-known/acme-challenge/")
{
let keys = self.keys.read();
if let Some(value) = keys.get(token) {
return Ok(value.clone().into_response());
if let Some(value) = self.keys.get(token) {
return Ok(value.into_response());
}
}

Expand Down
21 changes: 12 additions & 9 deletions poem/src/listener/acme/listener.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use std::{
collections::HashMap,
io::{Error as IoError, ErrorKind, Result as IoResult},
sync::{Arc, Weak},
time::{Duration, UNIX_EPOCH},
};

use http::uri::Scheme;
use parking_lot::RwLock;
use rcgen::{
Certificate, CertificateParams, CustomExtension, DistinguishedName, PKCS_ECDSA_P256_SHA256,
};
Expand All @@ -26,7 +24,7 @@ use crate::{
client::AcmeClient,
jose,
resolver::{ResolveServerCert, ACME_TLS_ALPN_NAME},
AutoCert, ChallengeType,
AutoCert, ChallengeType, Http01TokensMap,
},
Acceptor, HandshakeStream, Listener,
},
Expand Down Expand Up @@ -244,6 +242,7 @@ fn gen_acme_cert(domain: &str, acme_hash: &[u8]) -> IoResult<CertifiedKey> {
))
}

/// The result of [`issue_cert`] function.
pub struct IssueCertResult {
pub private_pem: String,
pub public_pem: Vec<u8>,
Expand All @@ -255,15 +254,15 @@ pub struct IssueCertResult {
///
/// It is up to the caller to make use of the returned certificate, this function does
/// nothing outside for the ACME protocol procedure.
pub async fn issue_cert(
pub async fn issue_cert<T: AsRef<str>>(
client: &mut AcmeClient,
resolver: &ResolveServerCert,
domains: &Vec<String>,
domains: &[T],
challenge_type: ChallengeType,
keys_for_http01: Option<&Arc<RwLock<HashMap<String, String>>>>,
keys_for_http01: Option<&Http01TokensMap>,
) -> IoResult<IssueCertResult> {
tracing::debug!("issue certificate");
let order_resp = client.new_order(&domains).await?;
let order_resp = client.new_order(domains).await?;

// trigger challenge
let mut valid = false;
Expand All @@ -286,7 +285,6 @@ pub async fn issue_cert(
match challenge_type {
ChallengeType::Http01 => {
if let Some(keys) = &keys_for_http01 {
let mut keys = keys.write();
let key_authorization =
jose::key_authorization(&client.key_pair, &challenge.token)?;
keys.insert(challenge.token.to_string(), key_authorization);
Expand Down Expand Up @@ -341,7 +339,12 @@ pub async fn issue_cert(
}

// send csr
let mut params = CertificateParams::new(domains.clone());
let mut params = CertificateParams::new(
domains
.iter()
.map(|domain| domain.as_ref().to_string())
.collect::<Vec<_>>(),
);
params.distinguished_name = DistinguishedName::new();
params.alg = &PKCS_ECDSA_P256_SHA256;
let cert = Certificate::from_params(params).map_err(|err| {
Expand Down
2 changes: 1 addition & 1 deletion poem/src/listener/acme/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ mod serde;
pub use auto_cert::AutoCert;
pub use builder::AutoCertBuilder;
pub use client::AcmeClient;
pub use endpoint::{new_http01_key_map, Http01Endpoint};
pub use endpoint::{Http01Endpoint, Http01TokensMap};
pub use listener::{issue_cert, AutoCertAcceptor, AutoCertListener, ResolvedCertListener};
pub use protocol::ChallengeType;
pub use resolver::{seconds_until_expiry, ResolveServerCert};
Expand Down

0 comments on commit 2e05b48

Please sign in to comment.