Browse Source

Add an independent endpoint structure

Having the data relative to the endpoint in the certificate structure
makes no sense. There is no way to share it across certificates which is
sometimes needed. Also, having the other part of the endpoint data
(mostly nonce and rate limit) in different places makes it difficult to
maintain.
Hence, the endpoint structure has been created. For now it is quite
simple and does not handle every aspects of the endpoint, but this will
be implemented in the future.
pull/31/head
Rodolphe Breard 5 years ago
parent
commit
b288f2b32c
  1. 1
      acmed/Cargo.toml
  2. 7
      acmed/src/acme_proto.rs
  3. 4
      acmed/src/acme_proto/account.rs
  4. 5
      acmed/src/acme_proto/structs/account.rs
  5. 3
      acmed/src/certificate.rs
  6. 35
      acmed/src/config.rs
  7. 6
      acmed/src/endpoint.rs
  8. 3
      acmed/src/main.rs
  9. 31
      acmed/src/main_event_loop.rs

1
acmed/Cargo.toml

@ -20,6 +20,7 @@ http_req = "0.5"
log = "0.4"
nom = "5.0"
openssl-sys = "0.9"
reqwest = { version = "0.10", features = ["blocking"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
toml = "0.5"

7
acmed/src/acme_proto.rs

@ -3,6 +3,7 @@ use crate::acme_proto::structs::{
ApiError, Authorization, AuthorizationStatus, NewOrder, Order, OrderStatus,
};
use crate::certificate::Certificate;
use crate::endpoint::Endpoint;
use crate::jws::encode_kid;
use crate::storage;
use acme_common::crypto::Csr;
@ -66,7 +67,7 @@ macro_rules! set_empty_data_builder {
};
}
pub fn request_certificate(cert: &Certificate, root_certs: &[String]) -> Result<(), Error> {
pub fn request_certificate(cert: &Certificate, root_certs: &[String], endpoint: &mut Endpoint) -> Result<(), Error> {
let domains = cert
.domains
.iter()
@ -75,13 +76,13 @@ pub fn request_certificate(cert: &Certificate, root_certs: &[String]) -> Result<
let mut hook_datas = vec![];
// 1. Get the directory
let directory = http::get_directory(cert, root_certs, &cert.remote_url)?;
let directory = http::get_directory(cert, root_certs, &endpoint.url)?;
// 2. Get a first nonce
let nonce = http::get_nonce(cert, root_certs, &directory.new_nonce)?;
// 3. Get or create the account
let (account, nonce) = AccountManager::new(cert, &directory, &nonce, root_certs)?;
let (account, nonce) = AccountManager::new(cert, &directory, endpoint, &nonce, root_certs)?;
// 4. Create a new order
let new_order = NewOrder::new(&domains);

4
acmed/src/acme_proto/account.rs

@ -1,6 +1,7 @@
use crate::acme_proto::http;
use crate::acme_proto::structs::{Account, AccountResponse, Directory};
use crate::certificate::Certificate;
use crate::endpoint::Endpoint;
use crate::jws::algorithms::SignatureAlgorithm;
use crate::jws::encode_jwk;
use crate::storage;
@ -18,12 +19,13 @@ impl AccountManager {
pub fn new(
cert: &Certificate,
directory: &Directory,
endpoint: &Endpoint,
nonce: &str,
root_certs: &[String],
) -> Result<(Self, String), Error> {
// TODO: store the key id (account url)
let key_pair = storage::get_account_keypair(cert)?;
let account = Account::new(cert);
let account = Account::new(cert, endpoint);
let account = serde_json::to_string(&account)?;
let data_builder =
|n: &str| encode_jwk(&key_pair, account.as_bytes(), &directory.new_account, n);

5
acmed/src/acme_proto/structs/account.rs

@ -1,4 +1,5 @@
use crate::certificate::Certificate;
use crate::endpoint::Endpoint;
use acme_common::error::Error;
use serde::{Deserialize, Serialize};
use std::str::FromStr;
@ -12,10 +13,10 @@ pub struct Account {
}
impl Account {
pub fn new(cert: &Certificate) -> Self {
pub fn new(cert: &Certificate, endpoint: &Endpoint) -> Self {
Account {
contact: vec![format!("mailto:{}", cert.account.email)],
terms_of_service_agreed: cert.tos_agreed,
terms_of_service_agreed: endpoint.tos_agreed,
only_return_existing: false,
}
}

3
acmed/src/certificate.rs

@ -47,8 +47,7 @@ pub struct Certificate {
pub domains: Vec<Domain>,
pub algo: Algorithm,
pub kp_reuse: bool,
pub remote_url: String,
pub tos_agreed: bool,
pub endpoint_name: String,
pub hooks: Vec<Hook>,
pub account_directory: String,
pub crt_directory: String,

35
acmed/src/config.rs

@ -184,13 +184,14 @@ pub struct Endpoint {
}
impl Endpoint {
fn is_used(&self, config: &Config) -> bool {
for crt in config.certificate.iter() {
if crt.endpoint == self.name {
return true;
}
}
false
fn to_generic(&self, _cnf: &Config) -> Result<crate::endpoint::Endpoint, Error> {
// TODO: include rate limits using `cnf.get_rate_limit()`
let ep = crate::endpoint::Endpoint {
name: self.name.to_owned(),
url: self.url.to_owned(),
tos_agreed: self.tos_agreed,
};
Ok(ep)
}
}
@ -334,30 +335,16 @@ impl Certificate {
crt_directory.to_string()
}
fn get_endpoint(&self, cnf: &Config) -> Result<Endpoint, Error> {
pub fn get_endpoint(&self, cnf: &Config) -> Result<crate::endpoint::Endpoint, Error> {
for endpoint in cnf.endpoint.iter() {
if endpoint.name == self.endpoint {
return Ok(endpoint.clone());
let ep = endpoint.to_generic(cnf)?;
return Ok(ep);
}
}
Err(format!("{}: unknown endpoint.", self.endpoint).into())
}
pub fn get_remote_url(&self, cnf: &Config) -> Result<String, Error> {
let ep = self.get_endpoint(cnf)?;
Ok(ep.url)
}
pub fn get_endpoint_name(&self, cnf: &Config) -> Result<String, Error> {
let ep = self.get_endpoint(cnf)?;
Ok(ep.name)
}
pub fn get_tos_agreement(&self, cnf: &Config) -> Result<bool, Error> {
let ep = self.get_endpoint(cnf)?;
Ok(ep.tos_agreed)
}
pub fn get_hooks(&self, cnf: &Config) -> Result<Vec<hooks::Hook>, Error> {
let mut res = vec![];
for name in self.hooks.iter() {

6
acmed/src/endpoint.rs

@ -0,0 +1,6 @@
pub struct Endpoint {
pub name: String,
pub url: String,
pub tos_agreed: bool,
// TODO: rate limits
}

3
acmed/src/main.rs

@ -6,6 +6,7 @@ use log::error;
mod acme_proto;
mod certificate;
mod config;
mod endpoint;
mod hooks;
mod jws;
mod main_event_loop;
@ -120,7 +121,7 @@ fn main() {
);
let config_file = matches.value_of("config").unwrap_or(DEFAULT_CONFIG_FILE);
let srv = match MainEventLoop::new(&config_file, &root_certs) {
let mut srv = match MainEventLoop::new(&config_file, &root_certs) {
Ok(s) => s,
Err(e) => {
error!("{}", e);

31
acmed/src/main_event_loop.rs

@ -2,12 +2,14 @@ use crate::acme_proto::account::init_account;
use crate::acme_proto::request_certificate;
use crate::certificate::Certificate;
use crate::config;
use crate::endpoint::Endpoint;
use acme_common::error::Error;
use std::collections::HashMap;
use std::thread;
use std::time::Duration;
fn renew_certificate(crt: &Certificate, root_certs: &[String]) {
let (status, is_success) = match request_certificate(crt, root_certs) {
fn renew_certificate(crt: &Certificate, root_certs: &[String], endpoint: &mut Endpoint) {
let (status, is_success) = match request_certificate(crt, root_certs, endpoint) {
Ok(_) => ("Success.".to_string(), true),
Err(e) => {
let e = e.prefix("Unable to renew the certificate");
@ -27,6 +29,7 @@ fn renew_certificate(crt: &Certificate, root_certs: &[String]) {
pub struct MainEventLoop {
certs: Vec<Certificate>,
root_certs: Vec<String>,
endpoints: HashMap<String, Endpoint>,
}
impl MainEventLoop {
@ -34,15 +37,15 @@ impl MainEventLoop {
let cnf = config::from_file(config_file)?;
let mut certs = Vec::new();
let mut endpoints = HashMap::new();
for (i, crt) in cnf.certificate.iter().enumerate() {
let ep_name = crt.get_endpoint_name(&cnf)?;
let endpoint = crt.get_endpoint(&cnf)?;
let cert = Certificate {
account: crt.get_account(&cnf)?,
domains: crt.get_domains()?,
algo: crt.get_algorithm()?,
kp_reuse: crt.get_kp_reuse(),
remote_url: crt.get_remote_url(&cnf)?,
tos_agreed: crt.get_tos_agreement(&cnf)?,
endpoint_name: endpoint.name.clone(),
hooks: crt.get_hooks(&cnf)?,
account_directory: cnf.get_account_dir(),
crt_directory: crt.get_crt_dir(&cnf),
@ -57,6 +60,9 @@ impl MainEventLoop {
env: crt.env.to_owned(),
id: i + 1,
};
if ! endpoints.contains_key(&endpoint.name) {
endpoints.insert(endpoint.name.clone(), endpoint);
}
init_account(&cert)?;
certs.push(cert);
}
@ -64,23 +70,30 @@ impl MainEventLoop {
Ok(MainEventLoop {
certs,
root_certs: root_certs.iter().map(|v| (*v).to_string()).collect(),
endpoints,
})
}
pub fn run(&self) {
pub fn run(&mut self) {
loop {
self.renew_certificates();
thread::sleep(Duration::from_secs(crate::DEFAULT_SLEEP_TIME));
}
}
fn renew_certificates(&self) {
fn renew_certificates(&mut self) {
for crt in self.certs.iter() {
match crt.should_renew() {
Ok(true) => {
let root_certs = self.root_certs.clone();
let cert = (*crt).clone();
renew_certificate(&cert, &root_certs);
match self.endpoints.get_mut(&crt.endpoint_name) {
Some(mut endpoint) => {
renew_certificate(&crt, &root_certs, &mut endpoint);
},
None => {
crt.warn(&format!("{}: Endpoint not found", &crt.endpoint_name));
}
};
}
Ok(false) => {}
Err(e) => {

Loading…
Cancel
Save