fix: root user password reset (#8348)

This commit is contained in:
Hengfei Yang
2025-09-10 17:24:07 +08:00
committed by GitHub
parent aff48e3a56
commit 55a0c62d3f
5 changed files with 73 additions and 22 deletions
+9 -2
View File
@@ -170,15 +170,16 @@ pub async fn cli() -> Result<bool, anyhow::Error> {
// init infra, create data dir & tables
let cfg = config::get_config();
infra::init().await.expect("infra init failed");
db::org_users::cache().await?;
match name.as_str() {
"reset" => {
let component = command.get_one::<String>("component").unwrap();
match component.as_str() {
"root" => {
let _ = users::update_user(
let ret = users::update_user(
meta::organization::DEFAULT_ORG,
cfg.auth.root_user_email.as_str(),
false,
meta::user::UserUpdateMode::CliUpdate,
cfg.auth.root_user_email.as_str(),
meta::user::UpdateUser {
change_password: true,
@@ -198,6 +199,12 @@ pub async fn cli() -> Result<bool, anyhow::Error> {
},
)
.await?;
if !ret.status().is_success() {
return Err(anyhow::anyhow!(
"reset root user failed, error: {:?}",
ret.body()
));
}
}
"user" => {
db::user::reset().await?;
+17
View File
@@ -127,6 +127,23 @@ pub struct UpdateUser {
pub token: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, ToSchema)]
pub enum UserUpdateMode {
OtherUpdate,
SelfUpdate,
CliUpdate,
}
impl UserUpdateMode {
pub fn is_self_update(&self) -> bool {
self == &UserUpdateMode::SelfUpdate
}
pub fn is_cli_update(&self) -> bool {
self == &UserUpdateMode::CliUpdate
}
}
pub fn get_default_user_org() -> UserOrg {
UserOrg {
name: "".to_string(),
@@ -29,7 +29,7 @@ use crate::{
self,
http::HttpResponse as MetaHttpResponse,
service_account::{APIToken, ServiceAccountRequest, UpdateServiceAccountRequest},
user::{UpdateUser, UserRequest},
user::{UpdateUser, UserRequest, UserUpdateMode},
},
utils::auth::UserEmail,
},
@@ -226,7 +226,14 @@ pub async fn update(
};
let initiator_id = &user_email.user_id;
users::update_user(&org_id, &email_id, false, initiator_id, user).await
users::update_user(
&org_id,
&email_id,
UserUpdateMode::OtherUpdate,
initiator_id,
user,
)
.await
}
/// RemoveServiceAccount
+7 -3
View File
@@ -45,7 +45,7 @@ use crate::{
self,
user::{
AuthTokens, PostUserRequest, RolesResponse, SignInResponse, SignInUser, UpdateUser,
UserOrgRole, UserRequest, UserRoleRequest, get_roles,
UserOrgRole, UserRequest, UserRoleRequest, UserUpdateMode, get_roles,
},
},
utils::auth::{UserEmail, generate_presigned_url, is_valid_email},
@@ -245,8 +245,12 @@ pub async fn update(
});
}
let initiator_id = &user_email.user_id;
let self_update = user_email.user_id.eq(&email_id);
users::update_user(&org_id, &email_id, self_update, initiator_id, user).await
let update_mode = if user_email.user_id.eq(&email_id) {
UserUpdateMode::SelfUpdate
} else {
UserUpdateMode::OtherUpdate
};
users::update_user(&org_id, &email_id, update_mode, initiator_id, user).await
}
/// AddUserToOrganization
+31 -15
View File
@@ -44,7 +44,8 @@ use crate::{
http::HttpResponse as MetaHttpResponse,
organization::{DEFAULT_ORG, OrgRoleMapping},
user::{
UpdateUser, UserList, UserOrgRole, UserRequest, UserResponse, get_default_user_org,
UpdateUser, UserList, UserOrgRole, UserRequest, UserResponse, UserUpdateMode,
get_default_user_org,
},
},
utils::auth::{get_hash, get_role, is_root_user, is_valid_email},
@@ -246,9 +247,9 @@ pub async fn create_new_user(mut db_user: DBUser) -> Result<(), anyhow::Error> {
pub async fn update_user(
org_id: &str,
email: &str,
self_update: bool,
update_mode: UserUpdateMode,
initiator_id: &str,
user: UpdateUser,
mut user: UpdateUser,
) -> Result<HttpResponse, Error> {
let mut allow_password_update = false;
if !is_valid_email(email) {
@@ -258,9 +259,16 @@ pub async fn update_user(
)));
}
let is_email_root = is_root_user(email);
#[cfg(not(feature = "enterprise"))]
if is_email_root {
user.role = Some(crate::common::meta::user::UserRoleRequest {
role: UserRole::Root.to_string(),
custom: None,
});
}
// Only root user can update root user
if is_email_root && !self_update {
if is_email_root && !update_mode.is_self_update() && !update_mode.is_cli_update() {
return Ok(HttpResponse::BadRequest().json(MetaHttpResponse::message(
http::StatusCode::BAD_REQUEST,
"Root user cannot be updated",
@@ -307,7 +315,7 @@ pub async fn update_user(
"Updates not allowed with external users, please update with source system",
)));
}
if !self_update {
if !update_mode.is_self_update() {
if is_root_user(initiator_id) {
allow_password_update = true
} else {
@@ -325,14 +333,20 @@ pub async fn update_user(
}
}
}
if !self_update && local_user.role.eq(&UserRole::Root) {
if local_user.role.eq(&UserRole::Root)
&& !update_mode.is_self_update()
&& !update_mode.is_cli_update()
{
return Ok(HttpResponse::BadRequest().json(MetaHttpResponse::message(
http::StatusCode::BAD_REQUEST,
"Only root user can update its details",
)));
}
new_user = local_user.clone();
if self_update && user.old_password.is_some() && user.new_password.is_some() {
if update_mode.is_self_update()
&& user.old_password.is_some()
&& user.new_password.is_some()
{
if local_user.password.eq(&get_hash(
&user.clone().old_password.unwrap(),
&local_user.salt,
@@ -350,10 +364,12 @@ pub async fn update_user(
message,
)));
}
} else if self_update && user.new_password.is_some() && user.old_password.is_none()
} else if update_mode.is_self_update()
&& user.new_password.is_some()
&& user.old_password.is_none()
{
message = "Please provide existing password";
} else if !self_update
} else if !update_mode.is_self_update()
&& allow_password_update
&& user.new_password.is_some()
&& !local_user.is_external
@@ -378,7 +394,7 @@ pub async fn update_user(
}
if user.role.is_some()
&& !local_user.is_external
&& (!self_update
&& (!update_mode.is_self_update()
|| (local_user.role.eq(&UserRole::Admin)
// Editor can update other's roles, but viewer can update only self
|| local_user.role.eq(&UserRole::Editor)
@@ -393,7 +409,7 @@ pub async fn update_user(
new_role = Some(new_user.role.clone());
if local_user.role.eq(&UserRole::Root) && new_user.role.ne(&UserRole::Root) {
message = "Root user role cannot be changed";
} else if self_update && local_user.role < new_user.role {
} else if update_mode.is_self_update() && local_user.role < new_user.role {
message = "Self role cannot be upgraded";
} else if local_user.role.ne(&new_user.role) {
#[cfg(feature = "enterprise")]
@@ -1380,7 +1396,7 @@ mod tests {
let resp = update_user(
"dummy",
"user2@example.com",
true,
UserUpdateMode::SelfUpdate,
"user2@example.com",
UpdateUser {
token: Some("new_token".to_string()),
@@ -1402,7 +1418,7 @@ mod tests {
let resp = update_user(
"dummy",
"user2@example.com",
false,
UserUpdateMode::OtherUpdate,
"admin@zo.dev",
UpdateUser {
token: Some("new_token".to_string()),
@@ -1635,7 +1651,7 @@ mod tests {
let resp = update_user(
"dummy",
"invalid-email",
false,
UserUpdateMode::OtherUpdate,
"admin@zo.dev",
UpdateUser {
token: None,
@@ -1655,7 +1671,7 @@ mod tests {
let resp = update_user(
"dummy",
"nonexistent@example.com",
false,
UserUpdateMode::OtherUpdate,
"admin@zo.dev",
UpdateUser {
token: None,