user_operations: don't fetch auth_string/password, only check existence

This commit is contained in:
Oystein Kristoffer Tveit 2024-08-07 17:14:24 +02:00
parent d0b750cd33
commit a9b8f7cee7
Signed by: oysteikt
GPG Key ID: 9F2F7D8250F35146
3 changed files with 26 additions and 44 deletions

View File

@ -11,7 +11,7 @@ use crate::{
config::{get_config, mysql_connection_from_config, GlobalConfigArgs}, config::{get_config, mysql_connection_from_config, GlobalConfigArgs},
user_operations::{ user_operations::{
create_database_user, delete_database_user, get_all_database_users_for_unix_user, create_database_user, delete_database_user, get_all_database_users_for_unix_user,
password_is_set_for_database_user, set_password_for_database_user, user_exists, get_database_user_for_user, set_password_for_database_user, user_exists,
}, },
}, },
}; };
@ -150,22 +150,24 @@ async fn passwd(args: PasswdArgs, connection: &mut MySqlConnection) -> anyhow::R
async fn show(args: ShowArgs, connection: &mut MySqlConnection) -> anyhow::Result<()> { async fn show(args: ShowArgs, connection: &mut MySqlConnection) -> anyhow::Result<()> {
let users = if args.name.is_empty() { let users = if args.name.is_empty() {
let unix_user = get_current_unix_user()?; let unix_user = get_current_unix_user()?;
get_all_database_users_for_unix_user(&unix_user, connection) get_all_database_users_for_unix_user(&unix_user, connection).await?
.await?
.into_iter()
.map(|u| u.user)
.collect()
} else { } else {
filter_db_or_user_names(args.name, DbOrUser::User)? let filtered_usernames = filter_db_or_user_names(args.name, DbOrUser::User)?;
let mut result = Vec::with_capacity(filtered_usernames.len());
for username in filtered_usernames.iter() {
// TODO: fetch all users in one query
get_database_user_for_user(username, connection)
.await?
.map(|user| result.push(user));
}
result
}; };
for user in users { for user in users {
let password_is_set = password_is_set_for_database_user(&user, connection).await?; if user.has_password {
println!("User '{}': password set.", user.user);
match password_is_set { } else {
Some(true) => println!("User '{}': password set.", user), println!("User '{}': no password set.", user.user);
Some(false) => println!("User '{}': no password set.", user),
None => {}
} }
} }

View File

@ -197,7 +197,7 @@ async fn show_users(args: UserShowArgs, conn: &mut MySqlConnection) -> anyhow::R
println!( println!(
"User '{}': {}", "User '{}': {}",
&user.user, &user.user,
if !(user.authentication_string.is_empty() && user.password.is_empty()) { if user.has_password {
"password set." "password set."
} else { } else {
"no password set." "no password set."

View File

@ -93,30 +93,6 @@ pub async fn set_password_for_database_user(
Ok(()) Ok(())
} }
/// Helper struct to deserialize the query made in `password_is_set_for_database_user`.
#[derive(sqlx::FromRow)]
#[sqlx(transparent)]
struct PasswordIsSet(bool);
/// This function checks if a database user has a password set.
/// It returns `Ok(None)` if the user does not exist.
pub async fn password_is_set_for_database_user(
db_user: &str,
conn: &mut MySqlConnection,
) -> anyhow::Result<Option<bool>> {
let unix_user = crate::core::common::get_current_unix_user()?;
validate_user_name(db_user, &unix_user)?;
let user_has_password = sqlx::query_as::<_, PasswordIsSet>(
"SELECT authentication_string != '' FROM mysql.user WHERE User = ?",
)
.bind(db_user)
.fetch_optional(conn)
.await?;
Ok(user_has_password.map(|PasswordIsSet(is_set)| is_set))
}
/// This struct contains information about a database user. /// This struct contains information about a database user.
/// This can be extended if we need more information in the future. /// This can be extended if we need more information in the future.
#[derive(Debug, Clone, FromRow, Serialize, Deserialize)] #[derive(Debug, Clone, FromRow, Serialize, Deserialize)]
@ -127,10 +103,8 @@ pub struct DatabaseUser {
#[sqlx(rename = "Host")] #[sqlx(rename = "Host")]
pub host: String, pub host: String,
#[sqlx(rename = "Password")] #[sqlx(rename = "`Password` != '' OR `authentication_string` != ''")]
pub password: String, pub has_password: bool,
pub authentication_string: String,
} }
/// This function fetches all database users that have a prefix matching the /// This function fetches all database users that have a prefix matching the
@ -141,7 +115,10 @@ pub async fn get_all_database_users_for_unix_user(
) -> anyhow::Result<Vec<DatabaseUser>> { ) -> anyhow::Result<Vec<DatabaseUser>> {
let users = sqlx::query_as::<_, DatabaseUser>( let users = sqlx::query_as::<_, DatabaseUser>(
r#" r#"
SELECT `User`, `Host`, `Password`, `authentication_string` SELECT
`User`,
`Host`,
`Password` != '' OR `authentication_string` != ''
FROM `mysql`.`user` FROM `mysql`.`user`
WHERE `User` REGEXP ? WHERE `User` REGEXP ?
"#, "#,
@ -160,7 +137,10 @@ pub async fn get_database_user_for_user(
) -> anyhow::Result<Option<DatabaseUser>> { ) -> anyhow::Result<Option<DatabaseUser>> {
let user = sqlx::query_as::<_, DatabaseUser>( let user = sqlx::query_as::<_, DatabaseUser>(
r#" r#"
SELECT `User`, `Host`, `Password`, `authentication_string` SELECT
`User`,
`Host`,
`Password` != '' OR `authentication_string` != ''
FROM `mysql`.`user` FROM `mysql`.`user`
WHERE `User` = ? WHERE `User` = ?
"#, "#,