2021-11-03 08:09:19 +00:00
|
|
|
use crate::infra::cli::RunOpts;
|
2021-08-26 19:56:42 +00:00
|
|
|
use anyhow::{Context, Result};
|
2021-03-02 19:30:43 +00:00
|
|
|
use figment::{
|
|
|
|
providers::{Env, Format, Serialized, Toml},
|
|
|
|
Figment,
|
|
|
|
};
|
2021-11-03 08:09:19 +00:00
|
|
|
use lettre::message::Mailbox;
|
2021-08-31 14:29:49 +00:00
|
|
|
use lldap_auth::opaque::{server::ServerSetup, KeyPair};
|
2021-03-02 19:30:43 +00:00
|
|
|
use serde::{Deserialize, Serialize};
|
2021-03-02 19:13:58 +00:00
|
|
|
|
2021-11-03 08:09:19 +00:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)]
|
|
|
|
#[builder(pattern = "owned")]
|
|
|
|
pub struct MailOptions {
|
|
|
|
#[builder(default = "false")]
|
|
|
|
pub enable_password_reset: bool,
|
|
|
|
#[builder(default = "None")]
|
|
|
|
pub from: Option<Mailbox>,
|
|
|
|
#[builder(default = "None")]
|
|
|
|
pub reply_to: Option<Mailbox>,
|
|
|
|
#[builder(default = r#""localhost".to_string()"#)]
|
|
|
|
pub server: String,
|
|
|
|
#[builder(default = "587")]
|
|
|
|
pub port: u16,
|
|
|
|
#[builder(default = r#""admin".to_string()"#)]
|
|
|
|
pub user: String,
|
|
|
|
#[builder(default = r#""".to_string()"#)]
|
|
|
|
pub password: String,
|
|
|
|
#[builder(default = "true")]
|
|
|
|
pub tls_required: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::default::Default for MailOptions {
|
|
|
|
fn default() -> Self {
|
|
|
|
MailOptionsBuilder::default().build().unwrap()
|
|
|
|
}
|
|
|
|
}
|
2021-03-02 19:51:33 +00:00
|
|
|
|
2021-06-14 14:02:36 +00:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)]
|
|
|
|
#[builder(
|
|
|
|
pattern = "owned",
|
|
|
|
build_fn(name = "private_build", validate = "Self::validate")
|
|
|
|
)]
|
2021-03-02 19:30:43 +00:00
|
|
|
pub struct Configuration {
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = "3890")]
|
2021-03-02 22:07:01 +00:00
|
|
|
pub ldap_port: u16,
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = "6360")]
|
2021-03-02 22:07:01 +00:00
|
|
|
pub ldaps_port: u16,
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = "17170")]
|
2021-03-07 11:36:12 +00:00
|
|
|
pub http_port: u16,
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = r#"String::from("secretjwtsecret")"#)]
|
2021-05-12 18:42:15 +00:00
|
|
|
pub jwt_secret: String,
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = r#"String::from("dc=example,dc=com")"#)]
|
2021-03-16 17:27:31 +00:00
|
|
|
pub ldap_base_dn: String,
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = r#"String::from("admin")"#)]
|
2021-03-12 08:33:43 +00:00
|
|
|
pub ldap_user_dn: String,
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = r#"String::from("password")"#)]
|
2021-03-12 08:33:43 +00:00
|
|
|
pub ldap_user_pass: String,
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = r#"String::from("sqlite://users.db?mode=rwc")"#)]
|
2021-03-12 08:33:43 +00:00
|
|
|
pub database_url: String,
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = "false")]
|
2021-03-02 22:07:01 +00:00
|
|
|
pub verbose: bool,
|
2021-11-03 07:01:34 +00:00
|
|
|
#[builder(default = r#"String::from("server_key")"#)]
|
2021-06-14 14:02:36 +00:00
|
|
|
pub key_file: String,
|
2021-11-03 08:09:19 +00:00
|
|
|
#[builder(default)]
|
|
|
|
pub smtp_options: MailOptions,
|
2021-06-14 14:02:36 +00:00
|
|
|
#[serde(skip)]
|
|
|
|
#[builder(field(private), setter(strip_option))]
|
2021-06-23 18:33:36 +00:00
|
|
|
server_setup: Option<ServerSetup>,
|
2021-03-02 19:30:43 +00:00
|
|
|
}
|
|
|
|
|
2021-11-03 08:09:19 +00:00
|
|
|
impl std::default::Default for Configuration {
|
|
|
|
fn default() -> Self {
|
|
|
|
ConfigurationBuilder::default().build().unwrap()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-06-14 14:02:36 +00:00
|
|
|
impl ConfigurationBuilder {
|
|
|
|
pub fn build(self) -> Result<Configuration> {
|
2021-06-23 18:33:36 +00:00
|
|
|
let server_setup = get_server_setup(self.key_file.as_deref().unwrap_or("server_key"))?;
|
|
|
|
Ok(self.server_setup(server_setup).private_build()?)
|
2021-06-14 14:02:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn validate(&self) -> Result<(), String> {
|
2021-06-23 18:33:36 +00:00
|
|
|
if self.server_setup.is_none() {
|
2021-06-14 14:02:36 +00:00
|
|
|
Err("Don't use `private_build`, use `build` instead".to_string())
|
|
|
|
} else {
|
|
|
|
Ok(())
|
2021-03-02 19:30:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-02 20:43:26 +00:00
|
|
|
impl Configuration {
|
2021-06-23 18:33:36 +00:00
|
|
|
pub fn get_server_setup(&self) -> &ServerSetup {
|
|
|
|
self.server_setup.as_ref().unwrap()
|
|
|
|
}
|
|
|
|
|
2021-06-14 14:02:36 +00:00
|
|
|
pub fn get_server_keys(&self) -> &KeyPair {
|
2021-06-23 18:33:36 +00:00
|
|
|
self.get_server_setup().keypair()
|
2021-06-14 14:02:36 +00:00
|
|
|
}
|
|
|
|
|
2021-08-26 19:46:00 +00:00
|
|
|
fn merge_with_cli(mut self: Configuration, cli_opts: RunOpts) -> Configuration {
|
2021-11-09 09:29:46 +00:00
|
|
|
if cli_opts.general_config.verbose {
|
2021-03-02 22:07:01 +00:00
|
|
|
self.verbose = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(port) = cli_opts.ldap_port {
|
|
|
|
self.ldap_port = port;
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Some(port) = cli_opts.ldaps_port {
|
|
|
|
self.ldaps_port = port;
|
2021-03-02 21:03:58 +00:00
|
|
|
}
|
2021-03-02 20:43:26 +00:00
|
|
|
|
2021-11-03 08:09:19 +00:00
|
|
|
if let Some(port) = cli_opts.http_port {
|
|
|
|
self.http_port = port;
|
|
|
|
}
|
|
|
|
|
2021-03-02 22:07:01 +00:00
|
|
|
self
|
2021-03-02 20:43:26 +00:00
|
|
|
}
|
2021-06-14 14:02:36 +00:00
|
|
|
}
|
|
|
|
|
2021-06-23 18:33:36 +00:00
|
|
|
fn get_server_setup(file_path: &str) -> Result<ServerSetup> {
|
2021-06-14 14:02:36 +00:00
|
|
|
use std::path::Path;
|
|
|
|
let path = Path::new(file_path);
|
|
|
|
if path.exists() {
|
2021-08-26 19:56:42 +00:00
|
|
|
let bytes =
|
|
|
|
std::fs::read(file_path).context(format!("Could not read key file `{}`", file_path))?;
|
2021-06-23 18:33:36 +00:00
|
|
|
Ok(ServerSetup::deserialize(&bytes)?)
|
2021-06-14 14:02:36 +00:00
|
|
|
} else {
|
|
|
|
let mut rng = rand::rngs::OsRng;
|
2021-06-23 18:33:36 +00:00
|
|
|
let server_setup = ServerSetup::new(&mut rng);
|
2021-08-26 19:56:42 +00:00
|
|
|
std::fs::write(path, server_setup.serialize()).context(format!(
|
|
|
|
"Could not write the generated server setup to file `{}`",
|
|
|
|
file_path,
|
|
|
|
))?;
|
2021-06-23 18:33:36 +00:00
|
|
|
Ok(server_setup)
|
2021-06-14 14:02:36 +00:00
|
|
|
}
|
2021-03-02 20:43:26 +00:00
|
|
|
}
|
|
|
|
|
2021-08-26 19:46:00 +00:00
|
|
|
pub fn init(cli_opts: RunOpts) -> Result<Configuration> {
|
2021-11-09 09:29:46 +00:00
|
|
|
let config_file = cli_opts.general_config.config_file.clone();
|
2021-03-02 20:43:26 +00:00
|
|
|
|
2021-11-09 09:29:46 +00:00
|
|
|
println!(
|
|
|
|
"Loading configuration from {}",
|
|
|
|
cli_opts.general_config.config_file
|
|
|
|
);
|
2021-10-20 06:05:26 +00:00
|
|
|
|
2021-11-03 07:01:34 +00:00
|
|
|
let config: Configuration = Figment::from(Serialized::defaults(
|
|
|
|
ConfigurationBuilder::default().build().unwrap(),
|
|
|
|
))
|
|
|
|
.merge(Toml::file(config_file))
|
2021-11-03 08:09:19 +00:00
|
|
|
.merge(Env::prefixed("LLDAP_").split("__"))
|
2021-11-03 07:01:34 +00:00
|
|
|
.extract()?;
|
2021-03-02 19:30:43 +00:00
|
|
|
|
2021-06-14 14:02:36 +00:00
|
|
|
let mut config = config.merge_with_cli(cli_opts);
|
2021-06-23 18:33:36 +00:00
|
|
|
config.server_setup = Some(get_server_setup(&config.key_file)?);
|
2021-11-03 07:01:34 +00:00
|
|
|
if config.jwt_secret == "secretjwtsecret" {
|
|
|
|
println!("WARNING: Default JWT secret used! This is highly unsafe and can allow attackers to log in as admin.");
|
|
|
|
}
|
|
|
|
if config.ldap_user_pass == "password" {
|
|
|
|
println!("WARNING: Unsecure default admin password is used.");
|
|
|
|
}
|
2021-03-02 19:30:43 +00:00
|
|
|
Ok(config)
|
2021-03-02 19:13:58 +00:00
|
|
|
}
|