mirror of
https://github.com/lldap/lldap.git
synced 2024-11-25 09:06:03 +00:00
server: Allow password reset every time the server starts
This commit is contained in:
parent
6f7bfca682
commit
3ec44a58be
4 changed files with 92 additions and 10 deletions
|
@ -82,6 +82,7 @@
|
||||||
## Break glass in case of emergency: if you lost the admin password, you
|
## Break glass in case of emergency: if you lost the admin password, you
|
||||||
## can set this to true to force a reset of the admin password to the value
|
## can set this to true to force a reset of the admin password to the value
|
||||||
## of ldap_user_pass above.
|
## of ldap_user_pass above.
|
||||||
|
## Alternatively, you can set it to "always" to reset every time the server starts.
|
||||||
# force_ldap_user_pass_reset = false
|
# force_ldap_user_pass_reset = false
|
||||||
|
|
||||||
## Database URL.
|
## Database URL.
|
||||||
|
|
|
@ -1,10 +1,78 @@
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
use clap::{builder::EnumValueParser, Parser};
|
use clap::{builder::EnumValueParser, Parser};
|
||||||
use lettre::message::Mailbox;
|
use lettre::message::Mailbox;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use strum::{EnumString, IntoStaticStr};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use crate::infra::database_string::DatabaseUrl;
|
use crate::infra::database_string::DatabaseUrl;
|
||||||
|
|
||||||
|
// Can be deserialized from either a boolean or a string, to facilitate migration.
|
||||||
|
#[derive(Copy, Clone, Debug, Serialize, Default, EnumString, IntoStaticStr)]
|
||||||
|
#[strum(ascii_case_insensitive)]
|
||||||
|
pub enum TrueFalseAlways {
|
||||||
|
#[default]
|
||||||
|
False,
|
||||||
|
True,
|
||||||
|
Always,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TrueFalseAlways {
|
||||||
|
pub fn is_positive(&self) -> bool {
|
||||||
|
matches!(self, TrueFalseAlways::True | TrueFalseAlways::Always)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_yes(&self) -> bool {
|
||||||
|
matches!(self, TrueFalseAlways::True)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for TrueFalseAlways {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
use serde::de::{self};
|
||||||
|
|
||||||
|
struct Visitor;
|
||||||
|
|
||||||
|
impl<'de> serde::de::Visitor<'de> for Visitor {
|
||||||
|
type Value = TrueFalseAlways;
|
||||||
|
|
||||||
|
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
formatter.write_str("true, false or always")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
if value {
|
||||||
|
Ok(TrueFalseAlways::True)
|
||||||
|
} else {
|
||||||
|
Ok(TrueFalseAlways::False)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||||
|
where
|
||||||
|
E: de::Error,
|
||||||
|
{
|
||||||
|
match TrueFalseAlways::from_str(value) {
|
||||||
|
Ok(v) => Ok(v),
|
||||||
|
Err(_) => Err(de::Error::unknown_variant(
|
||||||
|
value,
|
||||||
|
&["true", "false", "always"],
|
||||||
|
)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
deserializer.deserialize_any(Visitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// lldap is a lightweight LDAP server
|
/// lldap is a lightweight LDAP server
|
||||||
#[derive(Debug, Parser, Clone)]
|
#[derive(Debug, Parser, Clone)]
|
||||||
#[clap(version, author)]
|
#[clap(version, author)]
|
||||||
|
@ -92,8 +160,10 @@ pub struct RunOpts {
|
||||||
pub database_url: Option<DatabaseUrl>,
|
pub database_url: Option<DatabaseUrl>,
|
||||||
|
|
||||||
/// Force admin password reset to the config value.
|
/// Force admin password reset to the config value.
|
||||||
#[clap(long, env = "LLDAP_FORCE_LADP_USER_PASS_RESET")]
|
/// If set to true, it will be a one-time reset that doesn't start the server.
|
||||||
pub force_ldap_user_pass_reset: Option<bool>,
|
/// You can set it to "always" to force a reset every time the server starts.
|
||||||
|
#[clap(long, env = "LLDAP_FORCE_LDAP_USER_PASS_RESET")]
|
||||||
|
pub force_ldap_user_pass_reset: Option<TrueFalseAlways>,
|
||||||
|
|
||||||
/// Force update of the private key after a key change.
|
/// Force update of the private key after a key change.
|
||||||
#[clap(long, env = "LLDAP_FORCE_UPDATE_PRIVATE_KEY")]
|
#[clap(long, env = "LLDAP_FORCE_UPDATE_PRIVATE_KEY")]
|
||||||
|
|
|
@ -4,7 +4,10 @@ use crate::{
|
||||||
types::{AttributeName, UserId},
|
types::{AttributeName, UserId},
|
||||||
},
|
},
|
||||||
infra::{
|
infra::{
|
||||||
cli::{GeneralConfigOpts, LdapsOpts, RunOpts, SmtpEncryption, SmtpOpts, TestEmailOpts},
|
cli::{
|
||||||
|
GeneralConfigOpts, LdapsOpts, RunOpts, SmtpEncryption, SmtpOpts, TestEmailOpts,
|
||||||
|
TrueFalseAlways,
|
||||||
|
},
|
||||||
database_string::DatabaseUrl,
|
database_string::DatabaseUrl,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -90,8 +93,8 @@ pub struct Configuration {
|
||||||
pub ldap_user_email: String,
|
pub ldap_user_email: String,
|
||||||
#[builder(default = r#"SecUtf8::from("password")"#)]
|
#[builder(default = r#"SecUtf8::from("password")"#)]
|
||||||
pub ldap_user_pass: SecUtf8,
|
pub ldap_user_pass: SecUtf8,
|
||||||
#[builder(default = "false")]
|
#[builder(default)]
|
||||||
pub force_ldap_user_pass_reset: bool,
|
pub force_ldap_user_pass_reset: TrueFalseAlways,
|
||||||
#[builder(default = "false")]
|
#[builder(default = "false")]
|
||||||
pub force_update_private_key: bool,
|
pub force_update_private_key: bool,
|
||||||
#[builder(default = r#"DatabaseUrl::from("sqlite://users.db?mode=rwc")"#)]
|
#[builder(default = r#"DatabaseUrl::from("sqlite://users.db?mode=rwc")"#)]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#![forbid(unsafe_code)]
|
#![forbid(unsafe_code)]
|
||||||
#![forbid(non_ascii_idents)]
|
#![forbid(non_ascii_idents)]
|
||||||
// TODO: Remove next line after upgrade to 1.77
|
// TODO: Remove next line when it stops warning about async functions.
|
||||||
#![allow(clippy::blocks_in_conditions)]
|
#![allow(clippy::blocks_in_conditions)]
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -28,7 +28,7 @@ use actix_server::ServerBuilder;
|
||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use futures_util::TryFutureExt;
|
use futures_util::TryFutureExt;
|
||||||
use sea_orm::{Database, DatabaseConnection};
|
use sea_orm::{Database, DatabaseConnection};
|
||||||
use tracing::*;
|
use tracing::{debug, error, info, instrument, span, warn, Instrument, Level};
|
||||||
|
|
||||||
mod domain;
|
mod domain;
|
||||||
mod infra;
|
mod infra;
|
||||||
|
@ -144,20 +144,28 @@ async fn set_up_server(config: Configuration) -> Result<ServerBuilder> {
|
||||||
.await
|
.await
|
||||||
.map_err(|e| anyhow!("Error setting up admin login/account: {:#}", e))
|
.map_err(|e| anyhow!("Error setting up admin login/account: {:#}", e))
|
||||||
.context("while creating the admin user")?;
|
.context("while creating the admin user")?;
|
||||||
} else if config.force_ldap_user_pass_reset {
|
} else if config.force_ldap_user_pass_reset.is_positive() {
|
||||||
warn!("Forcing admin password reset to the config-provided password");
|
let span = if config.force_ldap_user_pass_reset.is_yes() {
|
||||||
|
span!(
|
||||||
|
Level::WARN,
|
||||||
|
"Forcing admin password reset to the config-provided password"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
span!(Level::INFO, "Resetting admin password")
|
||||||
|
};
|
||||||
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,
|
||||||
)
|
)
|
||||||
|
.instrument(span)
|
||||||
.await
|
.await
|
||||||
.context(format!(
|
.context(format!(
|
||||||
"while resetting admin password for {}",
|
"while resetting admin password for {}",
|
||||||
&config.ldap_user_dn
|
&config.ldap_user_dn
|
||||||
))?;
|
))?;
|
||||||
}
|
}
|
||||||
if config.force_update_private_key || config.force_ldap_user_pass_reset {
|
if config.force_update_private_key || config.force_ldap_user_pass_reset.is_yes() {
|
||||||
bail!("Restart the server without --force-update-private-key or --force-ldap-user-pass-reset to continue.");
|
bail!("Restart the server without --force-update-private-key or --force-ldap-user-pass-reset to continue.");
|
||||||
}
|
}
|
||||||
let server_builder = infra::ldap_server::build_ldap_server(
|
let server_builder = infra::ldap_server::build_ldap_server(
|
||||||
|
|
Loading…
Reference in a new issue