mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-01-04 04:12:55 +00:00
feat: supports permission mode for static user provider (#7017)
* feat: supports permission mode for static user provider Signed-off-by: Dennis Zhuang <killme2008@gmail.com> * chore: style Signed-off-by: Dennis Zhuang <killme2008@gmail.com> * fix: comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Signed-off-by: Dennis Zhuang <killme2008@gmail.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -109,7 +109,6 @@ impl GreptimeDbStandaloneBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[must_use]
|
||||
pub fn with_plugin(self, plugin: Plugins) -> Self {
|
||||
Self {
|
||||
|
||||
@@ -17,9 +17,10 @@ use std::fmt::Display;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use auth::UserProviderRef;
|
||||
use auth::{DefaultPermissionChecker, PermissionCheckerRef, UserProviderRef};
|
||||
use axum::Router;
|
||||
use catalog::kvbackend::KvBackendCatalogManager;
|
||||
use common_base::Plugins;
|
||||
use common_config::Configurable;
|
||||
use common_meta::key::catalog_name::CatalogNameKey;
|
||||
use common_meta::key::schema_name::SchemaNameKey;
|
||||
@@ -373,6 +374,18 @@ async fn setup_standalone_instance(
|
||||
.await
|
||||
}
|
||||
|
||||
async fn setup_standalone_instance_with_plugins(
|
||||
test_name: &str,
|
||||
store_type: StorageType,
|
||||
plugins: Plugins,
|
||||
) -> GreptimeDbStandalone {
|
||||
GreptimeDbStandaloneBuilder::new(test_name)
|
||||
.with_default_store_type(store_type)
|
||||
.with_plugin(plugins)
|
||||
.build()
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn setup_test_http_app(store_type: StorageType, name: &str) -> (Router, TestGuard) {
|
||||
let instance = setup_standalone_instance(name, store_type).await;
|
||||
|
||||
@@ -406,7 +419,13 @@ pub async fn setup_test_http_app_with_frontend_and_user_provider(
|
||||
name: &str,
|
||||
user_provider: Option<UserProviderRef>,
|
||||
) -> (Router, TestGuard) {
|
||||
let instance = setup_standalone_instance(name, store_type).await;
|
||||
let plugins = Plugins::new();
|
||||
if let Some(user_provider) = user_provider.clone() {
|
||||
plugins.insert::<UserProviderRef>(user_provider.clone());
|
||||
plugins.insert::<PermissionCheckerRef>(DefaultPermissionChecker::arc());
|
||||
}
|
||||
|
||||
let instance = setup_standalone_instance_with_plugins(name, store_type, plugins).await;
|
||||
|
||||
create_test_table(instance.fe_instance(), "demo").await;
|
||||
|
||||
@@ -587,7 +606,13 @@ pub async fn setup_mysql_server_with_user_provider(
|
||||
name: &str,
|
||||
user_provider: Option<UserProviderRef>,
|
||||
) -> (TestGuard, Arc<Box<dyn Server>>) {
|
||||
let instance = setup_standalone_instance(name, store_type).await;
|
||||
let plugins = Plugins::new();
|
||||
if let Some(user_provider) = user_provider.clone() {
|
||||
plugins.insert::<UserProviderRef>(user_provider.clone());
|
||||
plugins.insert::<PermissionCheckerRef>(DefaultPermissionChecker::arc());
|
||||
}
|
||||
|
||||
let instance = setup_standalone_instance_with_plugins(name, store_type, plugins).await;
|
||||
|
||||
let runtime = RuntimeBuilder::default()
|
||||
.worker_threads(2)
|
||||
|
||||
@@ -150,7 +150,7 @@ pub async fn test_http_auth(store_type: StorageType) {
|
||||
common_telemetry::init_default_ut_logging();
|
||||
|
||||
let user_provider = user_provider_from_option(
|
||||
&"static_user_provider:cmd:greptime_user=greptime_pwd".to_string(),
|
||||
&"static_user_provider:cmd:greptime_user=greptime_pwd,readonly_user:ro=readonly_pwd,writeonly_user:wo=writeonly_pwd".to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -187,6 +187,65 @@ pub async fn test_http_auth(store_type: StorageType) {
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
// 4. readonly user cannot write
|
||||
let res = client
|
||||
.get("/v1/sql?db=public&sql=show tables;")
|
||||
.header(
|
||||
"Authorization",
|
||||
"basic cmVhZG9ubHlfdXNlcjpyZWFkb25seV9wd2Q=",
|
||||
)
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
let res = client
|
||||
.get("/v1/sql?db=public&sql=create table auth_test(ts timestamp time index);")
|
||||
.header(
|
||||
"Authorization",
|
||||
"basic cmVhZG9ubHlfdXNlcjpyZWFkb25seV9wd2Q=",
|
||||
)
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::FORBIDDEN);
|
||||
|
||||
// 5. writeonly user cannot read
|
||||
let res = client
|
||||
.get("/v1/sql?db=public&sql=show tables;")
|
||||
.header(
|
||||
"Authorization",
|
||||
"basic d3JpdGVvbmx5X3VzZXI6d3JpdGVvbmx5X3B3ZA==",
|
||||
)
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::FORBIDDEN);
|
||||
let res = client
|
||||
.get("/v1/sql?db=public&sql=create table auth_test(ts timestamp time index);")
|
||||
.header(
|
||||
"Authorization",
|
||||
"basic d3JpdGVvbmx5X3VzZXI6d3JpdGVvbmx5X3B3ZA==",
|
||||
)
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
let res = client
|
||||
.get("/v1/sql?db=public&sql=insert into auth_test values(1);")
|
||||
.header(
|
||||
"Authorization",
|
||||
"basic d3JpdGVvbmx5X3VzZXI6d3JpdGVvbmx5X3B3ZA==",
|
||||
)
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
let res = client
|
||||
.get("/v1/sql?db=public&sql=select * from auth_test;")
|
||||
.header(
|
||||
"Authorization",
|
||||
"basic d3JpdGVvbmx5X3VzZXI6d3JpdGVvbmx5X3B3ZA==",
|
||||
)
|
||||
.send()
|
||||
.await;
|
||||
assert_eq!(res.status(), StatusCode::FORBIDDEN);
|
||||
|
||||
guard.remove_all().await;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ macro_rules! sql_tests {
|
||||
|
||||
pub async fn test_mysql_auth(store_type: StorageType) {
|
||||
let user_provider = user_provider_from_option(
|
||||
&"static_user_provider:cmd:greptime_user=greptime_pwd".to_string(),
|
||||
&"static_user_provider:cmd:greptime_user=greptime_pwd,readonly_user:ro=readonly_pwd,writeonly_user:wo=writeonly_pwd".to_string(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -140,6 +140,46 @@ pub async fn test_mysql_auth(store_type: StorageType) {
|
||||
|
||||
assert!(conn_re.is_ok());
|
||||
|
||||
// 4. readonly user
|
||||
let conn_re = MySqlPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&format!("mysql://readonly_user:readonly_pwd@{addr}/public"))
|
||||
.await;
|
||||
assert!(conn_re.is_ok());
|
||||
let pool = conn_re.unwrap();
|
||||
let _ = pool.execute("SELECT 1").await.unwrap();
|
||||
let err = pool
|
||||
.execute("CREATE TABLE test (ts timestamp time index)")
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert!(
|
||||
err.to_string()
|
||||
.contains("(PermissionDenied): User is not authorized to perform this action"),
|
||||
"{}",
|
||||
err.to_string()
|
||||
);
|
||||
|
||||
// 5. writeonly user
|
||||
let conn_re = MySqlPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&format!(
|
||||
"mysql://writeonly_user:writeonly_pwd@{addr}/public"
|
||||
))
|
||||
.await;
|
||||
assert!(conn_re.is_ok());
|
||||
let pool = conn_re.unwrap();
|
||||
let _ = pool
|
||||
.execute("CREATE TABLE test (ts timestamp time index)")
|
||||
.await
|
||||
.unwrap();
|
||||
let err = pool.execute("SHOW TABLES").await.unwrap_err();
|
||||
assert!(
|
||||
err.to_string()
|
||||
.contains("(PermissionDenied): User is not authorized to perform this action"),
|
||||
"{}",
|
||||
err.to_string()
|
||||
);
|
||||
|
||||
let _ = fe_mysql_server.shutdown().await;
|
||||
guard.remove_all().await;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user