mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
server: Prevent passwords and secrets from being printed
This commit is contained in:
parent
617a0f53fa
commit
9124339b96
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -1803,6 +1803,7 @@ dependencies = [
|
|||||||
"orion",
|
"orion",
|
||||||
"rand 0.8.4",
|
"rand 0.8.4",
|
||||||
"sea-query",
|
"sea-query",
|
||||||
|
"secstr",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
@ -2757,6 +2758,16 @@ dependencies = [
|
|||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "secstr"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cce2c726741c320e5b8f1edd9a21b3c2c292ae94514afd001d41d81ba143dafc"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.4.2"
|
version = "2.4.2"
|
||||||
|
@ -83,5 +83,9 @@ features = ["with-chrono"]
|
|||||||
features = ["env", "toml"]
|
features = ["env", "toml"]
|
||||||
version = "*"
|
version = "*"
|
||||||
|
|
||||||
|
[dependencies.secstr]
|
||||||
|
features = ["serde"]
|
||||||
|
version = "*"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
mockall = "0.9.1"
|
mockall = "0.9.1"
|
||||||
|
@ -437,7 +437,7 @@ mod tests {
|
|||||||
let sql_pool = get_in_memory_db().await;
|
let sql_pool = get_in_memory_db().await;
|
||||||
let config = ConfigurationBuilder::default()
|
let config = ConfigurationBuilder::default()
|
||||||
.ldap_user_dn("admin".to_string())
|
.ldap_user_dn("admin".to_string())
|
||||||
.ldap_user_pass("test".to_string())
|
.ldap_user_pass(secstr::SecUtf8::from("test"))
|
||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let handler = SqlBackendHandler::new(config, sql_pool);
|
let handler = SqlBackendHandler::new(config, sql_pool);
|
||||||
|
@ -9,6 +9,7 @@ use async_trait::async_trait;
|
|||||||
use lldap_auth::opaque;
|
use lldap_auth::opaque;
|
||||||
use log::*;
|
use log::*;
|
||||||
use sea_query::{Expr, Iden, Query};
|
use sea_query::{Expr, Iden, Query};
|
||||||
|
use secstr::SecUtf8;
|
||||||
use sqlx::Row;
|
use sqlx::Row;
|
||||||
|
|
||||||
type SqlOpaqueHandler = SqlBackendHandler;
|
type SqlOpaqueHandler = SqlBackendHandler;
|
||||||
@ -83,7 +84,7 @@ impl SqlBackendHandler {
|
|||||||
impl LoginHandler for SqlBackendHandler {
|
impl LoginHandler for SqlBackendHandler {
|
||||||
async fn bind(&self, request: BindRequest) -> Result<()> {
|
async fn bind(&self, request: BindRequest) -> Result<()> {
|
||||||
if request.name == self.config.ldap_user_dn {
|
if request.name == self.config.ldap_user_dn {
|
||||||
if request.password == self.config.ldap_user_pass {
|
if SecUtf8::from(request.password) == self.config.ldap_user_pass {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
debug!(r#"Invalid password for LDAP bind user"#);
|
debug!(r#"Invalid password for LDAP bind user"#);
|
||||||
@ -220,11 +221,12 @@ impl OpaqueHandler for SqlOpaqueHandler {
|
|||||||
pub(crate) async fn register_password(
|
pub(crate) async fn register_password(
|
||||||
opaque_handler: &SqlOpaqueHandler,
|
opaque_handler: &SqlOpaqueHandler,
|
||||||
username: &str,
|
username: &str,
|
||||||
password: &str,
|
password: &SecUtf8,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut rng = rand::rngs::OsRng;
|
let mut rng = rand::rngs::OsRng;
|
||||||
use registration::*;
|
use registration::*;
|
||||||
let registration_start = opaque::client::registration::start_registration(password, &mut rng)?;
|
let registration_start =
|
||||||
|
opaque::client::registration::start_registration(password.unsecure(), &mut rng)?;
|
||||||
let start_response = opaque_handler
|
let start_response = opaque_handler
|
||||||
.registration_start(ClientRegistrationStartRequest {
|
.registration_start(ClientRegistrationStartRequest {
|
||||||
username: username.to_string(),
|
username: username.to_string(),
|
||||||
@ -321,7 +323,7 @@ mod tests {
|
|||||||
attempt_login(&opaque_handler, "bob", "bob00")
|
attempt_login(&opaque_handler, "bob", "bob00")
|
||||||
.await
|
.await
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
register_password(&opaque_handler, "bob", "bob00").await?;
|
register_password(&opaque_handler, "bob", &secstr::SecUtf8::from("bob00")).await?;
|
||||||
attempt_login(&opaque_handler, "bob", "wrong_password")
|
attempt_login(&opaque_handler, "bob", "wrong_password")
|
||||||
.await
|
.await
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
|
@ -6,6 +6,7 @@ use figment::{
|
|||||||
};
|
};
|
||||||
use lettre::message::Mailbox;
|
use lettre::message::Mailbox;
|
||||||
use lldap_auth::opaque::{server::ServerSetup, KeyPair};
|
use lldap_auth::opaque::{server::ServerSetup, KeyPair};
|
||||||
|
use secstr::SecUtf8;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)]
|
#[derive(Clone, Debug, Deserialize, Serialize, derive_builder::Builder)]
|
||||||
@ -23,8 +24,8 @@ pub struct MailOptions {
|
|||||||
pub port: u16,
|
pub port: u16,
|
||||||
#[builder(default = r#""admin".to_string()"#)]
|
#[builder(default = r#""admin".to_string()"#)]
|
||||||
pub user: String,
|
pub user: String,
|
||||||
#[builder(default = r#""".to_string()"#)]
|
#[builder(default = r#"SecUtf8::from("")"#)]
|
||||||
pub password: String,
|
pub password: SecUtf8,
|
||||||
#[builder(default = "true")]
|
#[builder(default = "true")]
|
||||||
pub tls_required: bool,
|
pub tls_required: bool,
|
||||||
}
|
}
|
||||||
@ -47,14 +48,14 @@ pub struct Configuration {
|
|||||||
pub ldaps_port: u16,
|
pub ldaps_port: u16,
|
||||||
#[builder(default = "17170")]
|
#[builder(default = "17170")]
|
||||||
pub http_port: u16,
|
pub http_port: u16,
|
||||||
#[builder(default = r#"String::from("secretjwtsecret")"#)]
|
#[builder(default = r#"SecUtf8::from("secretjwtsecret")"#)]
|
||||||
pub jwt_secret: String,
|
pub jwt_secret: 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#"String::from("admin")"#)]
|
#[builder(default = r#"String::from("admin")"#)]
|
||||||
pub ldap_user_dn: String,
|
pub ldap_user_dn: String,
|
||||||
#[builder(default = r#"String::from("password")"#)]
|
#[builder(default = r#"SecUtf8::from("password")"#)]
|
||||||
pub ldap_user_pass: String,
|
pub ldap_user_pass: SecUtf8,
|
||||||
#[builder(default = r#"String::from("sqlite://users.db?mode=rwc")"#)]
|
#[builder(default = r#"String::from("sqlite://users.db?mode=rwc")"#)]
|
||||||
pub database_url: String,
|
pub database_url: String,
|
||||||
#[builder(default = "false")]
|
#[builder(default = "false")]
|
||||||
@ -188,7 +189,7 @@ impl ConfigOverrider for SmtpOpts {
|
|||||||
config.smtp_options.user = user.clone();
|
config.smtp_options.user = user.clone();
|
||||||
}
|
}
|
||||||
if let Some(password) = &self.smtp_password {
|
if let Some(password) = &self.smtp_password {
|
||||||
config.smtp_options.password = password.clone();
|
config.smtp_options.password = SecUtf8::from(password.clone());
|
||||||
}
|
}
|
||||||
if let Some(tls_required) = self.smtp_tls_required {
|
if let Some(tls_required) = self.smtp_tls_required {
|
||||||
config.smtp_options.tls_required = tls_required;
|
config.smtp_options.tls_required = tls_required;
|
||||||
@ -219,10 +220,10 @@ where
|
|||||||
println!("Configuration: {:#?}", &config);
|
println!("Configuration: {:#?}", &config);
|
||||||
}
|
}
|
||||||
config.server_setup = Some(get_server_setup(&config.key_file)?);
|
config.server_setup = Some(get_server_setup(&config.key_file)?);
|
||||||
if config.jwt_secret == "secretjwtsecret" {
|
if config.jwt_secret == SecUtf8::from("secretjwtsecret") {
|
||||||
println!("WARNING: Default JWT secret used! This is highly unsafe and can allow attackers to log in as admin.");
|
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" {
|
if config.ldap_user_pass == SecUtf8::from("password") {
|
||||||
println!("WARNING: Unsecure default admin password is used.");
|
println!("WARNING: Unsecure default admin password is used.");
|
||||||
}
|
}
|
||||||
Ok(config)
|
Ok(config)
|
||||||
|
@ -22,7 +22,10 @@ pub fn send_test_email(to: Mailbox, options: &MailOptions) -> Result<()> {
|
|||||||
.to(to)
|
.to(to)
|
||||||
.subject("LLDAP test email")
|
.subject("LLDAP test email")
|
||||||
.body("The test is successful! You can send emails from LLDAP".to_string())?;
|
.body("The test is successful! You can send emails from LLDAP".to_string())?;
|
||||||
let creds = Credentials::new(options.user.clone(), options.password.clone());
|
let creds = Credentials::new(
|
||||||
|
options.user.clone(),
|
||||||
|
options.password.unsecure().to_string(),
|
||||||
|
);
|
||||||
let mailer = SmtpTransport::relay(&options.server)?
|
let mailer = SmtpTransport::relay(&options.server)?
|
||||||
.credentials(creds)
|
.credentials(creds)
|
||||||
.build();
|
.build();
|
||||||
|
@ -44,14 +44,14 @@ pub(crate) fn error_to_http_response(error: DomainError) -> HttpResponse {
|
|||||||
fn http_config<Backend>(
|
fn http_config<Backend>(
|
||||||
cfg: &mut web::ServiceConfig,
|
cfg: &mut web::ServiceConfig,
|
||||||
backend_handler: Backend,
|
backend_handler: Backend,
|
||||||
jwt_secret: String,
|
jwt_secret: secstr::SecUtf8,
|
||||||
jwt_blacklist: HashSet<u64>,
|
jwt_blacklist: HashSet<u64>,
|
||||||
) where
|
) where
|
||||||
Backend: TcpBackendHandler + BackendHandler + LoginHandler + OpaqueHandler + Sync + 'static,
|
Backend: TcpBackendHandler + BackendHandler + LoginHandler + OpaqueHandler + Sync + 'static,
|
||||||
{
|
{
|
||||||
cfg.app_data(web::Data::new(AppState::<Backend> {
|
cfg.app_data(web::Data::new(AppState::<Backend> {
|
||||||
backend_handler,
|
backend_handler,
|
||||||
jwt_key: Hmac::new_varkey(jwt_secret.as_bytes()).unwrap(),
|
jwt_key: Hmac::new_varkey(jwt_secret.unsecure().as_bytes()).unwrap(),
|
||||||
jwt_blacklist: RwLock::new(jwt_blacklist),
|
jwt_blacklist: RwLock::new(jwt_blacklist),
|
||||||
}))
|
}))
|
||||||
// Serve index.html and main.js, and default to index.html.
|
// Serve index.html and main.js, and default to index.html.
|
||||||
|
@ -20,10 +20,11 @@ mod domain;
|
|||||||
mod infra;
|
mod infra;
|
||||||
|
|
||||||
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();
|
||||||
assert!(
|
assert!(
|
||||||
config.ldap_user_pass.len() >= 8,
|
pass_length >= 8,
|
||||||
"Minimum password length is 8 characters, got {} characters",
|
"Minimum password length is 8 characters, got {} characters",
|
||||||
config.ldap_user_pass.len()
|
pass_length
|
||||||
);
|
);
|
||||||
handler
|
handler
|
||||||
.create_user(CreateUserRequest {
|
.create_user(CreateUserRequest {
|
||||||
|
Loading…
Reference in New Issue
Block a user