From 3605db9b05413bd5b8d90904554cd2a2efc91db2 Mon Sep 17 00:00:00 2001 From: Ashish Kolhe <35160958+oasisk@users.noreply.github.com> Date: Fri, 17 Feb 2023 07:20:39 +0530 Subject: [PATCH] root user fixes (#97) Co-authored-by: Hengfei Yang --- src/common/auth.rs | 22 +++++++++++++++++++- src/handler/grpc/auth/mod.rs | 6 +++--- src/handler/http/auth/mod.rs | 22 +------------------- src/handler/http/request/organization/mod.rs | 8 +++---- src/handler/http/request/users/mod.rs | 4 ++-- src/infra/config.rs | 1 + src/service/db/file_list/broadcast.rs | 6 +++--- src/service/db/user.rs | 5 ++++- src/service/search.rs | 6 +++--- src/service/users.rs | 9 +++----- 10 files changed, 45 insertions(+), 44 deletions(-) diff --git a/src/common/auth.rs b/src/common/auth.rs index 85864207d6..9c558eabef 100644 --- a/src/common/auth.rs +++ b/src/common/auth.rs @@ -14,7 +14,10 @@ use argon2::{password_hash::SaltString, Algorithm, Argon2, Params, PasswordHasher, Version}; -use crate::infra::config::PASSWORD_HASH; +use crate::{ + infra::config::{PASSWORD_HASH, USERS}, + meta::user::UserRole, +}; pub fn get_hash(pass: &str, salt: &str) -> String { let key = format!("{}{}", pass, salt); @@ -38,3 +41,20 @@ pub fn get_hash(pass: &str, salt: &str) -> String { } } } + +pub async fn is_root_user(user_id: &str) -> bool { + match USERS.get(user_id) { + Some(user) => user.role.eq(&UserRole::Root), + None => false, + } +} + +#[cfg(test)] +mod test_utils { + use super::*; + #[actix_web::test] + async fn test_is_root_user() { + let res = is_root_user("dummy").await; + assert_eq!(res, false) + } +} diff --git a/src/handler/grpc/auth/mod.rs b/src/handler/grpc/auth/mod.rs index 2e6d63438c..4cafb83ee9 100644 --- a/src/handler/grpc/auth/mod.rs +++ b/src/handler/grpc/auth/mod.rs @@ -14,7 +14,7 @@ use crate::{ common::auth::get_hash, - infra::config::{CONFIG, USERS}, + infra::config::{CONFIG, ROOT_USER}, }; use http_auth_basic::Credentials; use tonic::{Request, Status}; @@ -38,10 +38,10 @@ pub fn check_auth(req: Request<()>) -> Result, Status> { Err(_) => return Err(Status::unauthenticated("No valid auth token")), }; - let user = USERS.get(&CONFIG.auth.root_user_email).unwrap(); + let user = ROOT_USER.get("root").unwrap(); let in_pass = get_hash(&credentials.password, &user.salt); - if credentials.user_id.eq(&CONFIG.auth.root_user_email) + if credentials.user_id.eq(&user.email) && (user.password.eq(&credentials.password) || user.password.eq(&in_pass)) { Ok(req) diff --git a/src/handler/http/auth/mod.rs b/src/handler/http/auth/mod.rs index bebfbfd4d9..4860ffb88d 100644 --- a/src/handler/http/auth/mod.rs +++ b/src/handler/http/auth/mod.rs @@ -19,8 +19,7 @@ use actix_web::{ }; use actix_web_httpauth::extractors::basic::BasicAuth; -use crate::common::auth::get_hash; -use crate::infra::config::CONFIG; +use crate::common::auth::{get_hash, is_root_user}; use crate::meta::user::UserRole; use crate::service::users; @@ -93,22 +92,3 @@ pub async fn validate_credentials( Err(ErrorForbidden("Not allowed")) } } - -pub async fn is_root_user(user_id: &str) -> bool { - user_id.eq(&CONFIG.auth.root_user_email) -} - -#[cfg(test)] -mod test_utils { - use super::*; - #[actix_web::test] - async fn test_validate_credentials() { - let res = validate_credentials( - &CONFIG.auth.root_user_email, - &CONFIG.auth.root_user_password, - "index", - ) - .await; - assert_eq!(res.is_ok(), true) - } -} diff --git a/src/handler/http/request/organization/mod.rs b/src/handler/http/request/organization/mod.rs index afc7b90c03..85792d88da 100644 --- a/src/handler/http/request/organization/mod.rs +++ b/src/handler/http/request/organization/mod.rs @@ -17,8 +17,8 @@ use actix_web_httpauth::extractors::basic::BasicAuth; use serde::Serialize; use std::io::Error; -use crate::handler::http::auth::is_root_user; -use crate::infra::config::{CONFIG, USERS}; +use crate::common::auth::is_root_user; +use crate::infra::config::USERS; use crate::meta::organization::PasscodeResponse; use crate::service::organization::get_passcode; use crate::service::organization::{self, update_passcode}; @@ -81,7 +81,7 @@ pub async fn organizarions_by_username( }; for user in USERS.iter() { - if !user.key().ends_with(&CONFIG.auth.root_user_email) { + if !user.key().ends_with(&user_name) { let org = Organization { identifier: user.key().split('/').collect::>()[0].to_string(), label: user.key().split('/').collect::>()[0].to_string(), @@ -134,7 +134,7 @@ pub async fn organizations(credentials: BasicAuth) -> Result { if v { - if user.name == CONFIG.auth.root_user_email { + if is_root_user(&user.name).await { ret.insert("role", Value::String(UserRole::Admin.to_string())); } else if let Some(user) = users::get_user(Some(&org_id), &user.name).await { ret.insert("role", Value::String(user.role.to_string())); diff --git a/src/infra/config.rs b/src/infra/config.rs index e86409d937..7c8e111876 100644 --- a/src/infra/config.rs +++ b/src/infra/config.rs @@ -52,6 +52,7 @@ lazy_static! { pub static ref STREAM_SCHEMAS: DashMap> = DashMap::new(); pub static ref QUERY_FUNCTIONS: DashMap = DashMap::new(); pub static ref USERS: DashMap = DashMap::new(); + pub static ref ROOT_USER: DashMap = DashMap::new(); pub static ref PASSWORD_HASH: DashMap = DashMap::new(); #[derive(Debug)] pub static ref METRIC_CLUSTER_MAP: DashMap> = DashMap::new(); diff --git a/src/service/db/file_list/broadcast.rs b/src/service/db/file_list/broadcast.rs index b21b99f9a0..6d6cb7d882 100644 --- a/src/service/db/file_list/broadcast.rs +++ b/src/service/db/file_list/broadcast.rs @@ -20,7 +20,7 @@ use tonic::{codec::CompressionEncoding, metadata::MetadataValue, transport::Chan use crate::handler::grpc::cluster_rpc; use crate::infra::cluster; -use crate::infra::config::{CONFIG, USERS}; +use crate::infra::config::{CONFIG, ROOT_USER}; use crate::meta::common::FileKey; lazy_static! { @@ -61,8 +61,8 @@ async fn send_to_node( if cluster::ge_node_by_uuid(&node.uuid).is_none() { return Ok(()); } - let user = USERS.get(&CONFIG.auth.root_user_email).unwrap(); - let credentials = Credentials::new(&CONFIG.auth.root_user_password, &user.password); + let user = ROOT_USER.get("root").unwrap(); + let credentials = Credentials::new(&user.email, &user.password); let credentials = credentials.as_http_header(); let token: MetadataValue<_> = credentials.parse()?; let channel = Channel::from_shared(node.grpc_addr) diff --git a/src/service/db/user.rs b/src/service/db/user.rs index da9c4d302e..c327d32533 100644 --- a/src/service/db/user.rs +++ b/src/service/db/user.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use tracing::info_span; use crate::common::json; -use crate::infra::config::USERS; +use crate::infra::config::{ROOT_USER, USERS}; use crate::infra::db::Event; use crate::meta::user::User; @@ -95,6 +95,9 @@ pub async fn cache() -> Result<(), anyhow::Error> { for (item_key, item_value) in ret { let item_key = item_key.strip_prefix(key).unwrap(); let json_val: User = json::from_slice(&item_value).unwrap(); + if !item_key.contains('/') { + ROOT_USER.insert("root".to_string(), json_val.clone()); + } USERS.insert(item_key.to_string(), json_val); } log::info!("[TRACE] Users Cached"); diff --git a/src/service/search.rs b/src/service/search.rs index f4272ce4ac..b2575ea8ca 100644 --- a/src/service/search.rs +++ b/src/service/search.rs @@ -25,7 +25,7 @@ use uuid::Uuid; use crate::handler::grpc::cluster_rpc; use crate::infra::cluster; -use crate::infra::config::{CONFIG, USERS}; +use crate::infra::config::{CONFIG, ROOT_USER}; use crate::infra::db::etcd; use crate::meta; use crate::meta::search::Response; @@ -290,8 +290,8 @@ async fn search_in_cluster(req: cluster_rpc::SearchRequest) -> Result Result { let salt = Uuid::new_v4().to_string(); @@ -152,7 +149,7 @@ pub async fn update_user( pub async fn get_user(org_id: Option<&str>, name: &str) -> Option { let mut local_org = ""; - let user_key = if name.eq(&CONFIG.auth.root_user_email) { + let user_key = if is_root_user(name).await { name.to_owned() } else { match org_id {