feat(nacos): add access control and namespace administration
This commit is contained in:
59 files changed
+4563
-479
No files matched your search
@@ -8,9 +8,9 @@ pub use dbx_core::agent_connection::{
|
||||
};
|
||||
pub use dbx_core::connection::{
|
||||
agent_connect_timeout, connect_bare_metadata_pool, connect_mysql_metadata_pool, connection_configs_pool_equivalent,
|
||||
connection_url_for_endpoint, gaussdb_m_jdbc_config_for_endpoint, gaussdb_uses_m_jdbc_driver,
|
||||
metadata_connection_config, prestosql_jdbc_config_for_endpoint, probe_connection_endpoint,
|
||||
redacted_connection_url_for_endpoint, AppState, MysqlMode, PoolKind,
|
||||
connection_configs_session_credentials_compatible, connection_url_for_endpoint, gaussdb_m_jdbc_config_for_endpoint,
|
||||
gaussdb_uses_m_jdbc_driver, metadata_connection_config, prestosql_jdbc_config_for_endpoint,
|
||||
probe_connection_endpoint, redacted_connection_url_for_endpoint, AppState, MysqlMode, PoolKind,
|
||||
};
|
||||
use dbx_core::database_capabilities;
|
||||
use dbx_core::db;
|
||||
@@ -301,6 +301,37 @@ mod tests {
|
||||
config
|
||||
}
|
||||
|
||||
fn nacos_config(id: &str) -> ConnectionConfig {
|
||||
let mut config = mongodb_config();
|
||||
config.id = id.to_string();
|
||||
config.name = "Nacos".to_string();
|
||||
config.db_type = DatabaseType::Nacos;
|
||||
config.driver_profile = None;
|
||||
config.driver_label = None;
|
||||
config.url_params = None;
|
||||
config.host = "127.0.0.1".to_string();
|
||||
config.port = 8848;
|
||||
config.username = "ordinary-user".to_string();
|
||||
config.password.clear();
|
||||
config.database = None;
|
||||
config.connection_string = None;
|
||||
config.save_password = false;
|
||||
config.visible_databases = Some(vec!["namespace-a".to_string()]);
|
||||
config.external_config = Some(serde_json::json!({
|
||||
"implementation": "nacos",
|
||||
"versionMode": "v3",
|
||||
"apiPlane": "admin",
|
||||
"serverAddr": "http://127.0.0.1:8848",
|
||||
"managedNamespaces": ["namespace-a"],
|
||||
"auth": {
|
||||
"kind": "usernamePassword",
|
||||
"username": "ordinary-user",
|
||||
"password": "old-password"
|
||||
}
|
||||
}));
|
||||
config
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn sqlite_connect_from_config_restores_attached_databases() {
|
||||
let dir = std::env::temp_dir().join(format!("dbx-tauri-sqlite-attach-{}", uuid::Uuid::new_v4()));
|
||||
@@ -791,6 +822,41 @@ mod tests {
|
||||
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn sync_connection_configs_preserves_nacos_session_password_for_scope_updates() {
|
||||
let dir = std::env::temp_dir().join(format!("dbx-tauri-nacos-scope-{}", uuid::Uuid::new_v4()));
|
||||
std::fs::create_dir_all(&dir).unwrap();
|
||||
let storage = Storage::open(&dir.join("storage.db")).await.unwrap();
|
||||
let state = AppState::new_with_plugin_dir(storage, dir.join("plugins"));
|
||||
let initial = nacos_config("nacos-a");
|
||||
state.configs.write().await.insert(initial.id.clone(), initial.clone());
|
||||
let _ = state.session_credentials.set("", &initial.id, "new-password");
|
||||
state.session_credentials.set_for_purpose("", &initial.id, "nacos-primary-password", "new-password");
|
||||
|
||||
let mut scope_updated = initial.clone();
|
||||
scope_updated.visible_databases = Some(vec!["namespace-a".to_string(), "namespace-b".to_string()]);
|
||||
scope_updated.external_config.as_mut().unwrap()["managedNamespaces"] =
|
||||
serde_json::json!(["namespace-a", "namespace-b"]);
|
||||
let sync = sync_connection_configs(&state, std::slice::from_ref(&scope_updated)).await;
|
||||
|
||||
assert_eq!(sync.connection_pool_ids_to_drop.as_slice(), std::slice::from_ref(&initial.id));
|
||||
assert_eq!(state.session_credentials.get("", &initial.id).as_deref(), Some("new-password"));
|
||||
assert_eq!(
|
||||
state.session_credentials.get_for_purpose("", &initial.id, "nacos-primary-password").as_deref(),
|
||||
Some("new-password")
|
||||
);
|
||||
|
||||
let mut endpoint_updated = scope_updated;
|
||||
endpoint_updated.host = "nacos.internal".to_string();
|
||||
endpoint_updated.external_config.as_mut().unwrap()["serverAddr"] =
|
||||
serde_json::json!("http://nacos.internal:8848");
|
||||
sync_connection_configs(&state, std::slice::from_ref(&endpoint_updated)).await;
|
||||
assert!(!state.session_credentials.has("", &initial.id));
|
||||
assert_eq!(state.session_credentials.get_for_purpose("", &initial.id, "nacos-primary-password"), None);
|
||||
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -859,12 +925,14 @@ async fn sync_connection_configs(state: &AppState, configs: &[ConnectionConfig])
|
||||
if previous.db_type == DatabaseType::MessageQueue {
|
||||
mq_adapter_ids_to_drop.insert(config.id.clone());
|
||||
}
|
||||
if !connection_configs_session_credentials_compatible(&previous, config) {
|
||||
// 端点或认证身份变化后,旧密码不能安全复用。显示范围等本地设置
|
||||
// 不影响凭据归属,因此必须保留 no-save 连接的新会话密码。
|
||||
state.session_credentials.clear_connection(&config.id);
|
||||
}
|
||||
// 仅在真实连接参数变化时销毁池;save_password=false 连接因持久化
|
||||
// 空密码与运行态密码产生的差异被忽略(见 connection_configs_pool_equivalent)。
|
||||
if !connection_configs_pool_equivalent(&previous, config) {
|
||||
// 连接端点/认证参数已变:旧会话凭据不再适配,清除以便下次重新输入,
|
||||
// 避免复用旧密码去连新端点而直接认证失败。
|
||||
state.session_credentials.clear_connection(&config.id);
|
||||
connection_pool_ids_to_drop.insert(config.id.clone());
|
||||
}
|
||||
}
|
||||
@@ -1903,6 +1971,23 @@ pub async fn forget_session_credential(state: State<'_, Arc<AppState>>, connecti
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn replace_nacos_session_credential(
|
||||
state: State<'_, Arc<AppState>>,
|
||||
connection_id: String,
|
||||
username: String,
|
||||
password: String,
|
||||
) -> Result<(), String> {
|
||||
state
|
||||
.replace_nacos_session_credential(
|
||||
dbx_core::session_credentials::DESKTOP_OWNER,
|
||||
&connection_id,
|
||||
&username,
|
||||
&password,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// 清空全部运行期会话凭据(桌面端退出前调用;Web 端登出时走 `auth.rs logout`)。
|
||||
/// 密码只存在于本次进程内存,进程退出本就会丢失;显式清除用于退出前兜底。
|
||||
#[tauri::command]
|
||||
|
||||
@@ -10,8 +10,9 @@ use crate::commands::connection::AppState;
|
||||
pub async fn nacos_test_connection(
|
||||
state: State<'_, Arc<AppState>>,
|
||||
connection_id: String,
|
||||
force_refresh: Option<bool>,
|
||||
) -> Result<dbx_core::nacos::NacosConnectionInfo, String> {
|
||||
dbx_core::nacos::service::nacos_test_connection_core(&state, &connection_id).await
|
||||
dbx_core::nacos::service::nacos_test_connection_core(&state, &connection_id, force_refresh.unwrap_or(false)).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
@@ -48,6 +49,15 @@ pub async fn nacos_update_namespace(
|
||||
dbx_core::nacos::service::nacos_update_namespace_core(&state, &connection_id, req).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn nacos_delete_namespace(
|
||||
state: State<'_, Arc<AppState>>,
|
||||
connection_id: String,
|
||||
namespace_id: String,
|
||||
) -> Result<(), String> {
|
||||
dbx_core::nacos::service::nacos_delete_namespace_core(&state, &connection_id, namespace_id).await
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn nacos_list_configs(
|
||||
state: State<'_, Arc<AppState>>,
|
||||
|
||||
@@ -1622,6 +1622,7 @@ pub fn run() {
|
||||
commands::connection::close_database_connection,
|
||||
commands::connection::session_credential_status,
|
||||
commands::connection::forget_session_credential,
|
||||
commands::connection::replace_nacos_session_credential,
|
||||
commands::connection::clear_all_session_credentials,
|
||||
commands::connection::refresh_connections,
|
||||
commands::connection::check_connection_health,
|
||||
@@ -1954,6 +1955,7 @@ pub fn run() {
|
||||
commands::nacos_cmd::nacos_sidebar_snapshot,
|
||||
commands::nacos_cmd::nacos_create_namespace,
|
||||
commands::nacos_cmd::nacos_update_namespace,
|
||||
commands::nacos_cmd::nacos_delete_namespace,
|
||||
commands::nacos_cmd::nacos_list_configs,
|
||||
commands::nacos_cmd::nacos_get_config,
|
||||
commands::nacos_cmd::nacos_publish_config,
|
||||
|
||||
Reference in new issue
Block a user