Prevent starting up if the JWT secret is not given

Similarly, don't create the admin if the password is not given
This commit is contained in:
Valentin Tolmer 2024-12-23 23:03:27 +01:00 committed by nitnelave
parent 1f26262e13
commit f417427635
9 changed files with 114 additions and 45 deletions

View File

@ -216,6 +216,8 @@ jobs:
LLDAP_database_url: postgres://lldapuser:lldappass@localhost/lldap LLDAP_database_url: postgres://lldapuser:lldappass@localhost/lldap
LLDAP_ldap_port: 3890 LLDAP_ldap_port: 3890
LLDAP_http_port: 17170 LLDAP_http_port: 17170
LLDAP_JWT_SECRET: verysecret
LLDAP_LDAP_USER_PASS: password
- name: Run lldap with mariadb DB (MySQL Compatible) and healthcheck - name: Run lldap with mariadb DB (MySQL Compatible) and healthcheck
@ -227,6 +229,8 @@ jobs:
LLDAP_database_url: mysql://lldapuser:lldappass@localhost/lldap LLDAP_database_url: mysql://lldapuser:lldappass@localhost/lldap
LLDAP_ldap_port: 3891 LLDAP_ldap_port: 3891
LLDAP_http_port: 17171 LLDAP_http_port: 17171
LLDAP_JWT_SECRET: verysecret
LLDAP_LDAP_USER_PASS: password
- name: Run lldap with sqlite DB and healthcheck - name: Run lldap with sqlite DB and healthcheck
@ -238,6 +242,8 @@ jobs:
LLDAP_database_url: sqlite://users.db?mode=rwc LLDAP_database_url: sqlite://users.db?mode=rwc
LLDAP_ldap_port: 3892 LLDAP_ldap_port: 3892
LLDAP_http_port: 17172 LLDAP_http_port: 17172
LLDAP_JWT_SECRET: verysecret
LLDAP_LDAP_USER_PASS: password
- name: Check DB container logs - name: Check DB container logs
run: | run: |
@ -324,9 +330,9 @@ jobs:
sleep 10s sleep 10s
bin/lldap healthcheck bin/lldap healthcheck
env: env:
LLDAP_database_url: sqlite://users.db?mode=rwc LLDAP_DATABASE_URL: sqlite://users.db?mode=rwc
LLDAP_ldap_port: 3890 LLDAP_LDAP_PORT: 3890
LLDAP_http_port: 17170 LLDAP_HTTP_PORT: 17170
LLDAP_LDAP_USER_PASS: ldappass LLDAP_LDAP_USER_PASS: ldappass
LLDAP_JWT_SECRET: somejwtsecret LLDAP_JWT_SECRET: somejwtsecret
@ -350,8 +356,11 @@ jobs:
sed -i -r -e "s/X'([[:xdigit:]]+'[^'])/'\\\x\\1/g" -e ":a; s/(INSERT INTO (user_attribute_schema|jwt_storage)\(.*\) VALUES\(.*),1([^']*\);)$/\1,true\3/; s/(INSERT INTO (user_attribute_schema|jwt_storage)\(.*\) VALUES\(.*),0([^']*\);)$/\1,false\3/; ta" -e '1s/^/BEGIN;\n/' -e '$aCOMMIT;' ./dump.sql sed -i -r -e "s/X'([[:xdigit:]]+'[^'])/'\\\x\\1/g" -e ":a; s/(INSERT INTO (user_attribute_schema|jwt_storage)\(.*\) VALUES\(.*),1([^']*\);)$/\1,true\3/; s/(INSERT INTO (user_attribute_schema|jwt_storage)\(.*\) VALUES\(.*),0([^']*\);)$/\1,false\3/; ta" -e '1s/^/BEGIN;\n/' -e '$aCOMMIT;' ./dump.sql
- name: Create schema on postgres - name: Create schema on postgres
env:
LLDAP_DATABASE_URL: postgres://lldapuser:lldappass@localhost:5432/lldap
LLDAP_JWT_SECRET: somejwtsecret
run: | run: |
bin/lldap create_schema -d postgres://lldapuser:lldappass@localhost:5432/lldap bin/lldap create_schema
- name: Copy converted db to postgress and import - name: Copy converted db to postgress and import
run: | run: |
@ -368,7 +377,10 @@ jobs:
sed -i '1 i\SET FOREIGN_KEY_CHECKS = 0;' ./dump.sql sed -i '1 i\SET FOREIGN_KEY_CHECKS = 0;' ./dump.sql
- name: Create schema on mariadb - name: Create schema on mariadb
run: bin/lldap create_schema -d mysql://lldapuser:lldappass@localhost:3306/lldap env:
LLDAP_DATABASE_URL: mysql://lldapuser:lldappass@localhost:3306/lldap
LLDAP_JWT_SECRET: somejwtsecret
run: bin/lldap create_schema
- name: Copy converted db to mariadb and import - name: Copy converted db to mariadb and import
run: | run: |
@ -384,7 +396,10 @@ jobs:
sed -i '1 i\SET FOREIGN_KEY_CHECKS = 0;' ./dump.sql sed -i '1 i\SET FOREIGN_KEY_CHECKS = 0;' ./dump.sql
- name: Create schema on mysql - name: Create schema on mysql
run: bin/lldap create_schema -d mysql://lldapuser:lldappass@localhost:3307/lldap env:
LLDAP_DATABASE_URL: mysql://lldapuser:lldappass@localhost:3307/lldap
LLDAP_JWT_SECRET: somejwtsecret
run: bin/lldap create_schema
- name: Copy converted db to mysql and import - name: Copy converted db to mysql and import
run: | run: |
@ -399,10 +414,9 @@ jobs:
sleep 10s sleep 10s
bin/lldap healthcheck bin/lldap healthcheck
env: env:
LLDAP_database_url: postgres://lldapuser:lldappass@localhost:5432/lldap LLDAP_DATABASE_URL: postgres://lldapuser:lldappass@localhost:5432/lldap
LLDAP_ldap_port: 3891 LLDAP_LDAP_PORT: 3891
LLDAP_http_port: 17171 LLDAP_HTTP_PORT: 17171
LLDAP_LDAP_USER_PASS: ldappass
LLDAP_JWT_SECRET: somejwtsecret LLDAP_JWT_SECRET: somejwtsecret
- name: Run lldap with mariaDB and healthcheck again - name: Run lldap with mariaDB and healthcheck again
@ -411,9 +425,9 @@ jobs:
sleep 10s sleep 10s
bin/lldap healthcheck bin/lldap healthcheck
env: env:
LLDAP_database_url: mysql://lldapuser:lldappass@localhost:3306/lldap LLDAP_DATABASE_URL: mysql://lldapuser:lldappass@localhost:3306/lldap
LLDAP_ldap_port: 3892 LLDAP_LDAP_PORT: 3892
LLDAP_http_port: 17172 LLDAP_HTTP_PORT: 17172
LLDAP_JWT_SECRET: somejwtsecret LLDAP_JWT_SECRET: somejwtsecret
- name: Run lldap with mysql and healthcheck again - name: Run lldap with mysql and healthcheck again
@ -422,9 +436,9 @@ jobs:
sleep 10s sleep 10s
bin/lldap healthcheck bin/lldap healthcheck
env: env:
LLDAP_database_url: mysql://lldapuser:lldappass@localhost:3307/lldap LLDAP_DATABASE_URL: mysql://lldapuser:lldappass@localhost:3307/lldap
LLDAP_ldap_port: 3893 LLDAP_LDAP_PORT: 3893
LLDAP_http_port: 17173 LLDAP_HTTP_PORT: 17173
LLDAP_JWT_SECRET: somejwtsecret LLDAP_JWT_SECRET: somejwtsecret
- name: Test Dummy User Postgres - name: Test Dummy User Postgres

View File

@ -156,6 +156,7 @@ services:
- LLDAP_JWT_SECRET=REPLACE_WITH_RANDOM - LLDAP_JWT_SECRET=REPLACE_WITH_RANDOM
- LLDAP_KEY_SEED=REPLACE_WITH_RANDOM - LLDAP_KEY_SEED=REPLACE_WITH_RANDOM
- LLDAP_LDAP_BASE_DN=dc=example,dc=com - LLDAP_LDAP_BASE_DN=dc=example,dc=com
- LLDAP_LDAP_USER_PASS=adminPas$word
# If using LDAPS, set enabled true and configure cert and key path # If using LDAPS, set enabled true and configure cert and key path
# - LLDAP_LDAPS_OPTIONS__ENABLED=true # - LLDAP_LDAPS_OPTIONS__ENABLED=true
# - LLDAP_LDAPS_OPTIONS__CERT_FILE=/path/to/certfile.crt # - LLDAP_LDAPS_OPTIONS__CERT_FILE=/path/to/certfile.crt
@ -713,6 +714,9 @@ modern identity protocols, check out Kanidm.
If you just set up the server, can get to the login page but the password you If you just set up the server, can get to the login page but the password you
set isn't working, try the following: set isn't working, try the following:
- If you have changed the admin password in the config after the first run, it
won't be used (unless you force its use with `force_ldap_user_pass_reset`).
The config password is only for the initial admin creation.
- (For docker): Make sure that the `/data` folder is persistent, either to a - (For docker): Make sure that the `/data` folder is persistent, either to a
docker volume or mounted from the host filesystem. docker volume or mounted from the host filesystem.
- Check if there is a `lldap_config.toml` file (either in `/data` for docker - Check if there is a `lldap_config.toml` file (either in `/data` for docker

View File

@ -314,8 +314,8 @@ pub struct UserRestrictedListerBackendHandler<'a, Handler> {
} }
#[async_trait] #[async_trait]
impl<'a, Handler: ReadSchemaBackendHandler + Sync> ReadSchemaBackendHandler impl<Handler: ReadSchemaBackendHandler + Sync> ReadSchemaBackendHandler
for UserRestrictedListerBackendHandler<'a, Handler> for UserRestrictedListerBackendHandler<'_, Handler>
{ {
async fn get_schema(&self) -> Result<Schema> { async fn get_schema(&self) -> Result<Schema> {
let mut schema = self.handler.get_schema().await?; let mut schema = self.handler.get_schema().await?;
@ -331,8 +331,8 @@ impl<'a, Handler: ReadSchemaBackendHandler + Sync> ReadSchemaBackendHandler
} }
#[async_trait] #[async_trait]
impl<'a, Handler: UserListerBackendHandler + Sync> UserListerBackendHandler impl<Handler: UserListerBackendHandler + Sync> UserListerBackendHandler
for UserRestrictedListerBackendHandler<'a, Handler> for UserRestrictedListerBackendHandler<'_, Handler>
{ {
async fn list_users( async fn list_users(
&self, &self,
@ -354,8 +354,8 @@ impl<'a, Handler: UserListerBackendHandler + Sync> UserListerBackendHandler
} }
#[async_trait] #[async_trait]
impl<'a, Handler: GroupListerBackendHandler + Sync> GroupListerBackendHandler impl<Handler: GroupListerBackendHandler + Sync> GroupListerBackendHandler
for UserRestrictedListerBackendHandler<'a, Handler> for UserRestrictedListerBackendHandler<'_, Handler>
{ {
async fn list_groups(&self, filters: Option<GroupRequestFilter>) -> Result<Vec<Group>> { async fn list_groups(&self, filters: Option<GroupRequestFilter>) -> Result<Vec<Group>> {
let group_filter = self let group_filter = self
@ -379,7 +379,7 @@ pub trait UserAndGroupListerBackendHandler:
} }
#[async_trait] #[async_trait]
impl<'a, Handler: GroupListerBackendHandler + UserListerBackendHandler + Sync> impl<Handler: GroupListerBackendHandler + UserListerBackendHandler + Sync>
UserAndGroupListerBackendHandler for UserRestrictedListerBackendHandler<'a, Handler> UserAndGroupListerBackendHandler for UserRestrictedListerBackendHandler<'_, Handler>
{ {
} }

View File

@ -37,7 +37,7 @@ impl<'de> Deserialize<'de> for TrueFalseAlways {
struct Visitor; struct Visitor;
impl<'de> serde::de::Visitor<'de> for Visitor { impl serde::de::Visitor<'_> for Visitor {
type Value = TrueFalseAlways; type Value = TrueFalseAlways;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {

View File

@ -97,16 +97,16 @@ pub struct Configuration {
pub http_host: String, pub http_host: String,
#[builder(default = "17170")] #[builder(default = "17170")]
pub http_port: u16, pub http_port: u16,
#[builder(default = r#"SecUtf8::from("secretjwtsecret")"#)] #[builder(default)]
pub jwt_secret: SecUtf8, pub jwt_secret: Option<SecUtf8>,
#[builder(default = r#"String::from("dc=example,dc=com")"#)] #[builder(default = r#"String::from("dc=example,dc=com")"#)]
pub ldap_base_dn: String, pub ldap_base_dn: String,
#[builder(default = r#"UserId::new("admin")"#)] #[builder(default = r#"UserId::new("admin")"#)]
pub ldap_user_dn: UserId, pub ldap_user_dn: UserId,
#[builder(default)] #[builder(default)]
pub ldap_user_email: String, pub ldap_user_email: String,
#[builder(default = r#"SecUtf8::from("password")"#)] #[builder(default)]
pub ldap_user_pass: SecUtf8, pub ldap_user_pass: Option<SecUtf8>,
#[builder(default)] #[builder(default)]
pub force_ldap_user_pass_reset: TrueFalseAlways, pub force_ldap_user_pass_reset: TrueFalseAlways,
#[builder(default = "false")] #[builder(default = "false")]
@ -607,11 +607,24 @@ where
.unwrap_or_default(), .unwrap_or_default(),
figment_config, figment_config,
)?); )?);
if config.jwt_secret == SecUtf8::from("secretjwtsecret") { if config.jwt_secret.is_none() {
println!("WARNING: Default JWT secret used! This is highly unsafe and can allow attackers to log in as admin."); use rand::{seq::SliceRandom, Rng};
} struct Symbols;
if config.ldap_user_pass == SecUtf8::from("password") {
println!("WARNING: Unsecure default admin password is used."); impl rand::prelude::Distribution<char> for Symbols {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> char {
*b"01234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+,-./:;<=>?_~!@#$%^&*()[]{}:;".choose(rng).unwrap() as char
}
}
bail!("The JWT secret must be initialized to a random string, preferably at least 32 characters long. \
Either set the `jwt_secret` config value or the `LLDAP_JWT_SECRET` environment variable. \
You can generate the value by running\n\
LC_ALL=C tr -dc 'A-Za-z0-9!#%&'\\''()*+,-./:;<=>?@[\\]^_{{|}}~' </dev/urandom | head -c 32; echo ''\n\
or you can use this random value: {}",
rand::thread_rng()
.sample_iter(&Symbols)
.take(32)
.collect::<String>());
} }
if config.smtp_options.tls_required.is_some() { if config.smtp_options.tls_required.is_some() {
println!("DEPRECATED: smtp_options.tls_required field is deprecated, it never did anything. You can replace it with smtp_options.smtp_encryption."); println!("DEPRECATED: smtp_options.tls_required field is deprecated, it never did anything. You can replace it with smtp_options.smtp_encryption.");
@ -669,7 +682,9 @@ mod tests {
fn figment_location_extraction_key_file() { fn figment_location_extraction_key_file() {
Jail::expect_with(|jail| { Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?; jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_KEY_SEED", "a123"); jail.set_env("LLDAP_KEY_SEED", "a123");
jail.set_env("LLDAP_JWT_SECRET", "secret");
let ignore_keys = ["key_file", "cert_file"]; let ignore_keys = ["key_file", "cert_file"];
let figment_config = Figment::from(Serialized::defaults( let figment_config = Figment::from(Serialized::defaults(
ConfigurationBuilder::default().private_build().unwrap(), ConfigurationBuilder::default().private_build().unwrap(),
@ -696,7 +711,9 @@ mod tests {
fn check_server_setup_key_extraction_seed_success_with_nonexistant_file() { fn check_server_setup_key_extraction_seed_success_with_nonexistant_file() {
Jail::expect_with(|jail| { Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?; jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_KEY_SEED", "a123"); jail.set_env("LLDAP_KEY_SEED", "a123");
jail.set_env("LLDAP_JWT_SECRET", "secret");
init(default_run_opts()).unwrap(); init(default_run_opts()).unwrap();
Ok(()) Ok(())
}); });
@ -706,7 +723,9 @@ mod tests {
fn check_server_setup_key_extraction_seed_failure_with_existing_file() { fn check_server_setup_key_extraction_seed_failure_with_existing_file() {
Jail::expect_with(|jail| { Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?; jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_KEY_SEED", "a123"); jail.set_env("LLDAP_KEY_SEED", "a123");
jail.set_env("LLDAP_JWT_SECRET", "secret");
write_random_key(jail, "test"); write_random_key(jail, "test");
init(default_run_opts()).unwrap_err(); init(default_run_opts()).unwrap_err();
Ok(()) Ok(())
@ -717,6 +736,8 @@ mod tests {
fn check_server_setup_key_extraction_file_success_with_existing_file() { fn check_server_setup_key_extraction_file_success_with_existing_file() {
Jail::expect_with(|jail| { Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?; jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
write_random_key(jail, "test"); write_random_key(jail, "test");
init(default_run_opts()).unwrap(); init(default_run_opts()).unwrap();
Ok(()) Ok(())
@ -727,6 +748,8 @@ mod tests {
fn check_server_setup_key_extraction_file_success_with_nonexistent_file() { fn check_server_setup_key_extraction_file_success_with_nonexistent_file() {
Jail::expect_with(|jail| { Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?; jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
init(default_run_opts()).unwrap(); init(default_run_opts()).unwrap();
Ok(()) Ok(())
}); });
@ -736,6 +759,8 @@ mod tests {
fn check_server_setup_key_extraction_file_with_previous_different_file() { fn check_server_setup_key_extraction_file_with_previous_different_file() {
Jail::expect_with(|jail| { Jail::expect_with(|jail| {
jail.create_file("lldap_config.toml", r#"key_file = "test""#)?; jail.create_file("lldap_config.toml", r#"key_file = "test""#)?;
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
write_random_key(jail, "test"); write_random_key(jail, "test");
let config = init(default_run_opts()).unwrap(); let config = init(default_run_opts()).unwrap();
let info = config.get_private_key_info(); let info = config.get_private_key_info();
@ -766,6 +791,8 @@ mod tests {
#[test] #[test]
fn check_server_setup_key_extraction_file_to_seed() { fn check_server_setup_key_extraction_file_to_seed() {
Jail::expect_with(|jail| { Jail::expect_with(|jail| {
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
jail.create_file("lldap_config.toml", "")?; jail.create_file("lldap_config.toml", "")?;
write_random_key(jail, "server_key"); write_random_key(jail, "server_key");
init(default_run_opts()).unwrap(); init(default_run_opts()).unwrap();
@ -782,6 +809,8 @@ mod tests {
#[test] #[test]
fn check_server_setup_key_extraction_file_to_seed_removed_file() { fn check_server_setup_key_extraction_file_to_seed_removed_file() {
Jail::expect_with(|jail| { Jail::expect_with(|jail| {
jail.clear_env();
jail.set_env("LLDAP_JWT_SECRET", "secret");
jail.create_file("lldap_config.toml", "")?; jail.create_file("lldap_config.toml", "")?;
write_random_key(jail, "server_key"); write_random_key(jail, "server_key");
let config = init(default_run_opts()).unwrap(); let config = init(default_run_opts()).unwrap();

View File

@ -189,7 +189,7 @@ pub async fn build_tcp_server<Backend>(
where where
Backend: TcpBackendHandler + BackendHandler + LoginHandler + OpaqueHandler + Clone + 'static, Backend: TcpBackendHandler + BackendHandler + LoginHandler + OpaqueHandler + Clone + 'static,
{ {
let jwt_secret = config.jwt_secret.clone(); let jwt_secret = config.jwt_secret.clone().unwrap();
let jwt_blacklist = backend_handler let jwt_blacklist = backend_handler
.get_jwt_blacklist() .get_jwt_blacklist()
.await .await

View File

@ -33,8 +33,17 @@ use tracing::{debug, error, info, instrument, span, warn, Instrument, Level};
mod domain; mod domain;
mod infra; mod infra;
const ADMIN_PASSWORD_MISSING_ERROR : &str = "The LDAP admin password must be initialized. \
Either set the `ldap_user_pass` config value or the `LLDAP_LDAP_USER_PASS` environment variable. \
A minimum of 8 characters is recommended.";
async fn create_admin_user(handler: &SqlBackendHandler, config: &Configuration) -> Result<()> { async fn create_admin_user(handler: &SqlBackendHandler, config: &Configuration) -> Result<()> {
let pass_length = config.ldap_user_pass.unsecure().len(); let pass_length = config
.ldap_user_pass
.as_ref()
.expect(ADMIN_PASSWORD_MISSING_ERROR)
.unsecure()
.len();
assert!( assert!(
pass_length >= 8, pass_length >= 8,
"Minimum password length is 8 characters, got {} characters", "Minimum password length is 8 characters, got {} characters",
@ -48,7 +57,11 @@ async fn create_admin_user(handler: &SqlBackendHandler, config: &Configuration)
..Default::default() ..Default::default()
}) })
.and_then(|_| { .and_then(|_| {
register_password(handler, config.ldap_user_dn.clone(), &config.ldap_user_pass) register_password(
handler,
config.ldap_user_dn.clone(),
config.ldap_user_pass.as_ref().unwrap(),
)
}) })
.await .await
.context("Error creating admin user")?; .context("Error creating admin user")?;
@ -161,7 +174,10 @@ async fn set_up_server(config: Configuration) -> Result<ServerBuilder> {
register_password( register_password(
&backend_handler, &backend_handler,
config.ldap_user_dn.clone(), config.ldap_user_dn.clone(),
&config.ldap_user_pass, config
.ldap_user_pass
.as_ref()
.expect(ADMIN_PASSWORD_MISSING_ERROR),
) )
.instrument(span) .instrument(span)
.await .await

View File

@ -3,6 +3,8 @@ use std::env::var;
pub const DB_KEY: &str = "LLDAP_DATABASE_URL"; pub const DB_KEY: &str = "LLDAP_DATABASE_URL";
pub const PRIVATE_KEY_SEED: &str = "LLDAP_KEY_SEED"; pub const PRIVATE_KEY_SEED: &str = "LLDAP_KEY_SEED";
pub const JWT_SECRET: &str = "LLDAP_JWT_SECRET";
pub const LDAP_USER_PASSWORD: &str = "LLDAP_LDAP_USER_PASS";
pub fn database_url() -> String { pub fn database_url() -> String {
let url = var(DB_KEY).ok(); let url = var(DB_KEY).ok();

View File

@ -43,14 +43,13 @@ const MAX_HEALTHCHECK_ATTEMPS: u8 = 10;
impl LLDAPFixture { impl LLDAPFixture {
pub fn new() -> Self { pub fn new() -> Self {
let mut cmd = create_lldap_command(); let child = create_lldap_command("run")
cmd.arg("run"); .arg("--verbose")
cmd.arg("--verbose"); .spawn()
let child = cmd.spawn().expect("Unable to start server"); .expect("Unable to start server");
let mut started = false; let mut started = false;
for _ in 0..MAX_HEALTHCHECK_ATTEMPS { for _ in 0..MAX_HEALTHCHECK_ATTEMPS {
let status = create_lldap_command() let status = create_lldap_command("healthcheck")
.arg("healthcheck")
.status() .status()
.expect("healthcheck fail"); .expect("healthcheck fail");
if status.success() { if status.success() {
@ -229,7 +228,7 @@ pub fn new_id(prefix: Option<&str>) -> String {
} }
} }
fn create_lldap_command() -> Command { fn create_lldap_command(subcommand: &str) -> Command {
let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).expect("cargo bin not found"); let mut cmd = Command::cargo_bin(env!("CARGO_PKG_NAME")).expect("cargo bin not found");
// This gives us the absolute path of the repo base instead of running it in server/ // This gives us the absolute path of the repo base instead of running it in server/
let path = canonicalize("..").expect("canonical path"); let path = canonicalize("..").expect("canonical path");
@ -237,5 +236,10 @@ fn create_lldap_command() -> Command {
cmd.current_dir(path); cmd.current_dir(path);
cmd.env(env::DB_KEY, db_url); cmd.env(env::DB_KEY, db_url);
cmd.env(env::PRIVATE_KEY_SEED, "Random value"); cmd.env(env::PRIVATE_KEY_SEED, "Random value");
cmd.env(env::JWT_SECRET, "Random value");
cmd.env(env::LDAP_USER_PASSWORD, "password");
cmd.arg(subcommand);
cmd.arg("--config-file=/dev/null");
cmd.arg("--server-key-file=''");
cmd cmd
} }