Make passwords optional when registering a new user

This commit is contained in:
Valentin Tolmer 2021-06-14 16:32:10 +02:00 committed by nitnelave
parent 3c916a2530
commit 973fac4bb8
6 changed files with 72 additions and 39 deletions

View File

@ -67,7 +67,7 @@ impl Component for CreateUserForm {
display_name: Some(get_element("displayname")), display_name: Some(get_element("displayname")),
first_name: Some(get_element("firstname")), first_name: Some(get_element("firstname")),
last_name: Some(get_element("lastname")), last_name: Some(get_element("lastname")),
password: get_element("password"), password: Some(get_element("password")),
}; };
self.create_user(req); self.create_user(req);
} }

View File

@ -56,7 +56,7 @@ pub struct CreateUserRequest {
pub display_name: Option<String>, pub display_name: Option<String>,
pub first_name: Option<String>, pub first_name: Option<String>,
pub last_name: Option<String>, pub last_name: Option<String>,
pub password: String, pub password: Option<String>,
} }
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)] #[derive(PartialEq, Eq, Debug, Serialize, Deserialize, Clone, Default)]

View File

@ -110,14 +110,20 @@ impl BackendHandler for SqlBackendHandler {
.and_where(Expr::col(Users::UserId).eq(request.name.as_str())) .and_where(Expr::col(Users::UserId).eq(request.name.as_str()))
.to_string(DbQueryBuilder {}); .to_string(DbQueryBuilder {});
if let Ok(row) = sqlx::query(&query).fetch_one(&self.sql_pool).await { if let Ok(row) = sqlx::query(&query).fetch_one(&self.sql_pool).await {
if let Err(e) = passwords_match( if let Some(password_hash) =
&row.get::<Vec<u8>, _>(&*Users::PasswordHash.to_string()), row.get::<Option<Vec<u8>>, _>(&*Users::PasswordHash.to_string())
&request.password, {
self.config.get_server_keys().private(), if let Err(e) = passwords_match(
) { &&password_hash,
debug!(r#"Invalid password for "{}": {}"#, request.name, e); &request.password,
self.config.get_server_keys().private(),
) {
debug!(r#"Invalid password for "{}": {}"#, request.name, e);
} else {
return Ok(());
}
} else { } else {
return Ok(()); debug!(r#"User "{}" has no password"#, request.name);
} }
} else { } else {
debug!(r#"No user found for "{}""#, request.name); debug!(r#"No user found for "{}""#, request.name);
@ -233,29 +239,34 @@ impl BackendHandler for SqlBackendHandler {
} }
async fn create_user(&self, request: CreateUserRequest) -> Result<()> { async fn create_user(&self, request: CreateUserRequest) -> Result<()> {
let password_hash = let mut columns = vec![
get_password_file(&request.password, self.config.get_server_keys().public())? Users::UserId,
.serialize(); Users::Email,
Users::DisplayName,
Users::FirstName,
Users::LastName,
Users::CreationDate,
];
let mut values = vec![
request.user_id.into(),
request.email.into(),
request.display_name.map(Into::into).unwrap_or(Value::Null),
request.first_name.map(Into::into).unwrap_or(Value::Null),
request.last_name.map(Into::into).unwrap_or(Value::Null),
chrono::Utc::now().naive_utc().into(),
];
if let Some(pass) = request.password {
columns.push(Users::PasswordHash);
values.push(
get_password_file(&pass, self.config.get_server_keys().public())?
.serialize()
.into(),
);
}
let query = Query::insert() let query = Query::insert()
.into_table(Users::Table) .into_table(Users::Table)
.columns(vec![ .columns(columns)
Users::UserId, .values_panic(values)
Users::Email,
Users::DisplayName,
Users::FirstName,
Users::LastName,
Users::CreationDate,
Users::PasswordHash,
])
.values_panic(vec![
request.user_id.into(),
request.email.into(),
request.display_name.map(Into::into).unwrap_or(Value::Null),
request.first_name.map(Into::into).unwrap_or(Value::Null),
request.last_name.map(Into::into).unwrap_or(Value::Null),
chrono::Utc::now().naive_utc().into(),
password_hash.into(),
])
.to_string(DbQueryBuilder {}); .to_string(DbQueryBuilder {});
sqlx::query(&query).execute(&self.sql_pool).await?; sqlx::query(&query).execute(&self.sql_pool).await?;
Ok(()) Ok(())
@ -325,7 +336,18 @@ mod tests {
.create_user(CreateUserRequest { .create_user(CreateUserRequest {
user_id: name.to_string(), user_id: name.to_string(),
email: "bob@bob.bob".to_string(), email: "bob@bob.bob".to_string(),
password: pass.to_string(), password: Some(pass.to_string()),
..Default::default()
})
.await
.unwrap();
}
async fn insert_user_no_password(handler: &SqlBackendHandler, name: &str) {
handler
.create_user(CreateUserRequest {
user_id: name.to_string(),
email: "bob@bob.bob".to_string(),
..Default::default() ..Default::default()
}) })
.await .await
@ -399,6 +421,22 @@ mod tests {
.unwrap_err(); .unwrap_err();
} }
#[tokio::test]
async fn test_user_no_password() {
let sql_pool = get_initialized_db().await;
let config = get_default_config();
let handler = SqlBackendHandler::new(config, sql_pool.clone());
insert_user_no_password(&handler, "bob").await;
handler
.bind(BindRequest {
name: "bob".to_string(),
password: "bob00".to_string(),
})
.await
.unwrap_err();
}
#[tokio::test] #[tokio::test]
async fn test_list_users() { async fn test_list_users() {
let sql_pool = get_initialized_db().await; let sql_pool = get_initialized_db().await;

View File

@ -54,7 +54,7 @@ pub async fn init_table(pool: &Pool) -> sqlx::Result<()> {
.col(ColumnDef::new(Users::LastName).string_len(255)) .col(ColumnDef::new(Users::LastName).string_len(255))
.col(ColumnDef::new(Users::Avatar).binary()) .col(ColumnDef::new(Users::Avatar).binary())
.col(ColumnDef::new(Users::CreationDate).date_time().not_null()) .col(ColumnDef::new(Users::CreationDate).date_time().not_null())
.col(ColumnDef::new(Users::PasswordHash).binary().not_null()) .col(ColumnDef::new(Users::PasswordHash).binary())
.col(ColumnDef::new(Users::TotpSecret).string_len(64)) .col(ColumnDef::new(Users::TotpSecret).string_len(64))
.col(ColumnDef::new(Users::MfaType).string_len(64)) .col(ColumnDef::new(Users::MfaType).string_len(64))
.to_string(DbQueryBuilder {}), .to_string(DbQueryBuilder {}),

View File

@ -33,12 +33,7 @@ pub struct Configuration {
impl ConfigurationBuilder { impl ConfigurationBuilder {
#[cfg(test)] #[cfg(test)]
pub fn build(self) -> Result<Configuration> { pub fn build(self) -> Result<Configuration> {
let server_keys = get_server_keys( let server_keys = get_server_keys(&self.key_file.as_deref().unwrap_or("server_key"))?;
&self
.key_file
.as_deref()
.unwrap_or("server_key"),
)?;
Ok(self.server_keys(server_keys).private_build()?) Ok(self.server_keys(server_keys).private_build()?)
} }

View File

@ -17,7 +17,7 @@ async fn create_admin_user(handler: &SqlBackendHandler, config: &Configuration)
handler handler
.create_user(lldap_model::CreateUserRequest { .create_user(lldap_model::CreateUserRequest {
user_id: config.ldap_user_dn.clone(), user_id: config.ldap_user_dn.clone(),
password: config.ldap_user_pass.clone(), password: Some(config.ldap_user_pass.clone()),
..Default::default() ..Default::default()
}) })
.await .await