refactor: make access control a separate package (#422)

Co-authored-by: nathan <nathan@appflowy.io>
This commit is contained in:
Khor Shu Heng 2024-03-30 11:06:49 +08:00 committed by GitHub
parent 0f384a119a
commit ccd11f0b02
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 118 additions and 93 deletions

78
Cargo.lock generated
View File

@ -2,6 +2,27 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "access-control"
version = "0.1.0"
dependencies = [
"actix-http",
"anyhow",
"app-error",
"async-trait",
"casbin",
"database",
"database-entity",
"futures-util",
"lazy_static",
"prometheus-client",
"redis 0.25.2",
"sqlx",
"tokio",
"tokio-stream",
"tracing",
]
[[package]]
name = "actix"
version = "0.13.3"
@ -512,6 +533,7 @@ dependencies = [
name = "appflowy-cloud"
version = "0.1.0"
dependencies = [
"access-control",
"actix",
"actix-http",
"actix-identity",
@ -752,16 +774,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "atomic-write-file"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edcdbedc2236483ab103a53415653d6b4442ea6141baf1ffa85df29635e88436"
dependencies = [
"nix",
"rand 0.8.5",
]
[[package]]
name = "atomic_refcell"
version = "0.1.13"
@ -1213,9 +1225,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
[[package]]
name = "chrono"
version = "0.4.33"
version = "0.4.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb"
checksum = "8a0d04d43504c61aa6c7531f1871dd0d418d91130162063b789da00fd7057a5e"
dependencies = [
"android-tzdata",
"iana-time-zone",
@ -3368,17 +3380,6 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
[[package]]
name = "nix"
version = "0.27.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
dependencies = [
"bitflags 2.4.2",
"cfg-if",
"libc",
]
[[package]]
name = "no-std-compat"
version = "0.4.1"
@ -5201,9 +5202,9 @@ dependencies = [
[[package]]
name = "sqlx"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dba03c279da73694ef99763320dea58b51095dfe87d001b1d4b5fe78ba8763cf"
checksum = "c9a2ccff1a000a5a59cd33da541d9f2fdcd9e6e8229cc200565942bff36d0aaa"
dependencies = [
"sqlx-core",
"sqlx-macros",
@ -5214,9 +5215,9 @@ dependencies = [
[[package]]
name = "sqlx-core"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd"
checksum = "24ba59a9342a3d9bab6c56c118be528b27c9b60e490080e9711a04dccac83ef6"
dependencies = [
"ahash 0.8.7",
"atoi",
@ -5225,7 +5226,6 @@ dependencies = [
"chrono",
"crc",
"crossbeam-queue",
"dotenvy",
"either",
"event-listener",
"futures-channel",
@ -5260,9 +5260,9 @@ dependencies = [
[[package]]
name = "sqlx-macros"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89961c00dc4d7dffb7aee214964b065072bff69e36ddb9e2c107541f75e4f2a5"
checksum = "4ea40e2345eb2faa9e1e5e326db8c34711317d2b5e08d0d5741619048a803127"
dependencies = [
"proc-macro2",
"quote",
@ -5273,11 +5273,10 @@ dependencies = [
[[package]]
name = "sqlx-macros-core"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0bd4519486723648186a08785143599760f7cc81c52334a55d6a83ea1e20841"
checksum = "5833ef53aaa16d860e92123292f1f6a3d53c34ba8b1969f152ef1a7bb803f3c8"
dependencies = [
"atomic-write-file",
"dotenvy",
"either",
"heck",
@ -5300,9 +5299,9 @@ dependencies = [
[[package]]
name = "sqlx-mysql"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4"
checksum = "1ed31390216d20e538e447a7a9b959e06ed9fc51c37b514b46eb758016ecd418"
dependencies = [
"atoi",
"base64 0.21.7",
@ -5345,9 +5344,9 @@ dependencies = [
[[package]]
name = "sqlx-postgres"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24"
checksum = "7c824eb80b894f926f89a0b9da0c7f435d27cdd35b8c655b114e58223918577e"
dependencies = [
"atoi",
"base64 0.21.7",
@ -5374,7 +5373,6 @@ dependencies = [
"rust_decimal",
"serde",
"serde_json",
"sha1",
"sha2",
"smallvec",
"sqlx-core",
@ -5387,9 +5385,9 @@ dependencies = [
[[package]]
name = "sqlx-sqlite"
version = "0.7.3"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "210976b7d948c7ba9fced8ca835b11cbb2d677c59c79de41ac0d397e14547490"
checksum = "b244ef0a8414da0bed4bb1910426e890b19e5e9bccc27ada6b797d05c55ae0aa"
dependencies = [
"atoi",
"chrono",

View File

@ -8,7 +8,7 @@ edition = "2021"
[dependencies]
actix = "0.13.3"
actix-web = { version = "4.4.1", default-features = false, features = ["openssl", "compress-brotli", "compress-gzip"] }
actix-http = { version = "3.5.1", default-features = false, features = ["openssl", "compress-brotli", "compress-gzip"] }
actix-http = { workspace = true, default-features = false, features = ["openssl", "compress-brotli", "compress-gzip"] }
actix-rt = "2.9.0"
actix-web-actors = { version = "4.2.0" }
actix-service = "2.0.2"
@ -28,11 +28,11 @@ tokio = { workspace = true, features = [
"fs",
"time",
] }
tokio-stream = "0.1.14"
tokio-stream.workspace = true
tokio-util = { version = "0.7.10", features = ["io"] }
futures-util ={ version = "0.3.30" , features = ["std","io"] }
futures-util ={ workspace = true , features = ["std","io"] }
once_cell = "1.19.0"
chrono = { version = "0.4.31", features = ["serde", "clock"], default-features = false }
chrono = { version = "0.4.37", features = ["serde", "clock"], default-features = false }
derive_more = { version = "0.99" }
argon2 = { version = "0.5", features = ["std"] }
secrecy = { version = "0.8", features = ["serde"] }
@ -41,7 +41,7 @@ anyhow = "1.0.79"
thiserror = "1.0.56"
reqwest = { workspace = true, features = ["json", "rustls-tls", "cookies"] }
unicode-segmentation = "1.10"
lazy_static = "1.4.0"
lazy_static.workspace = true
fancy-regex = "0.11.0"
validator = "0.16.1"
bytes = "1.5.0"
@ -53,14 +53,14 @@ tracing = "0.1.40"
tracing-subscriber = { version = "0.3.18", features = ["registry", "env-filter", "ansi", "json"] }
tracing-bunyan-formatter = "0.3.9"
tracing-log = "0.1.4"
sqlx = { version = "0.7", default-features = false, features = ["runtime-tokio-rustls", "macros", "postgres", "uuid", "chrono", "migrate"] }
async-trait = "0.1.77"
prometheus-client = "0.22.0"
sqlx = { workspace = true, default-features = false, features = ["runtime-tokio-rustls", "macros", "postgres", "uuid", "chrono", "migrate"] }
async-trait.workspace = true
prometheus-client.workspace = true
itertools = "0.11"
uuid = "1.6.1"
tokio-tungstenite = { version = "0.20.1", features = ["native-tls"] }
prost = "0.12.3"
casbin = { version = "2.2.0", features = ["cached", "runtime-tokio", "incremental"] }
casbin.workspace = true
dotenvy = "0.15.7"
url = "2.5.0"
brotli = "3.4.0"
@ -77,12 +77,13 @@ collab-entity = { version = "0.1.0" }
#Local crate
snowflake = { path = "libs/snowflake" }
database = { path = "libs/database" }
database.workspace = true
appflowy-ai = { path = "libs/appflowy-ai" }
database-entity.workspace = true
gotrue = { path = "libs/gotrue" }
gotrue-entity = { path = "libs/gotrue-entity" }
infra = { path = "libs/infra" }
access-control.workspace = true
app-error = { workspace = true, features = ["sqlx_error", "actix_web_error", "tokio_error"] }
shared-entity = { path = "libs/shared-entity", features = ["cloud"] }
workspace-template = { workspace = true }
@ -133,6 +134,7 @@ members = [
"libs/app-error",
"libs/workspace-template",
"libs/encrypt",
"libs/access-control",
"libs/collab-rt-protocol",
"libs/collab-stream",
"libs/client-websocket",
@ -148,9 +150,14 @@ members = [
[workspace.dependencies]
collab-rt-entity = { path = "libs/collab-rt-entity" }
collab-rt-protocol = { path = "libs/collab-rt-protocol" }
database = { path = "libs/database" }
database-entity = { path = "libs/database-entity" }
shared-entity = { path = "libs/shared-entity" }
access-control = { path = "libs/access-control" }
app-error = { path = "libs/app-error" }
async-trait = "0.1.77"
prometheus-client = "0.22.0"
casbin = { version = "2.2.0", features = ["cached", "runtime-tokio", "incremental"] }
collab-stream = { path = "libs/collab-stream" }
serde_json = "1.0.111"
serde = { version = "1.0.195", features = ["derive"] }
@ -158,7 +165,10 @@ bytes = "1.5.0"
workspace-template = { path = "libs/workspace-template" }
uuid = { version = "1.6.1", features = ["v4"] }
anyhow = "1.0.79"
actix-http = { version = "3.5.1", default-features = false }
tokio = { version = "1.36.0", features = ["sync"] }
tokio-stream = "0.1.14"
futures-util = "0.3.30"
yrs = "0.17.2"
bincode = "1.3.3"
client-websocket = { path = "libs/client-websocket" }
@ -169,11 +179,13 @@ tracing = { version = "0.1.40"}
collab-entity = { version = "0.1.0" }
gotrue = { path = "libs/gotrue" }
redis = "0.25.2"
sqlx = { version = "0.7.4", default-features = false }
dashmap = "5.5.3"
futures = "0.3.30"
async-stream = "0.3.5"
reqwest = "0.11.26"
collab-rt = { path = "libs/collab-rt" }
lazy_static = "1.4.0"
[profile.release]
lto = true

View File

@ -0,0 +1,25 @@
[package]
name = "access-control"
version = "0.1.0"
edition = "2021"
[dependencies]
actix-http.workspace = true
app-error.workspace = true
anyhow.workspace = true
async-trait.workspace = true
casbin.workspace = true
database.workspace = true
database-entity.workspace = true
futures-util.workspace = true
lazy_static.workspace = true
prometheus-client.workspace = true
redis.workspace = true
sqlx = { workspace = true, default-features = false, features = ["postgres"] }
tracing.workspace = true
tokio = { workspace = true, features = [
"macros",
"rt",
"time",
] }
tokio-stream.workspace = true

View File

@ -1,15 +1,13 @@
use crate::biz::casbin::collab_ac::CollabAccessControlImpl;
use crate::biz::casbin::enforcer::{AFEnforcer, NoEnforceGroup};
use crate::enforcer::{AFEnforcer, NoEnforceGroup};
use crate::biz::casbin::workspace_ac::WorkspaceAccessControlImpl;
use std::cmp::Ordering;
use app_error::AppError;
use casbin::{CoreApi, DefaultModel, Enforcer, MgmtApi};
use database_entity::dto::{AFAccessLevel, AFRole};
use crate::biz::casbin::adapter::PgAdapter;
use crate::biz::casbin::metrics::{tick_metric, AccessControlMetrics};
use crate::adapter::PgAdapter;
use crate::metrics::{tick_metric, AccessControlMetrics};
use actix_http::Method;
use anyhow::anyhow;
@ -75,14 +73,6 @@ impl AccessControl {
self.change_tx.subscribe()
}
pub fn new_collab_access_control(&self) -> CollabAccessControlImpl {
CollabAccessControlImpl::new(self.clone())
}
pub fn new_workspace_access_control(&self) -> WorkspaceAccessControlImpl {
WorkspaceAccessControlImpl::new(self.clone())
}
pub async fn update_policy(
&self,
uid: &i64,

View File

@ -1,8 +1,8 @@
use crate::biz::casbin::access_control::{ObjectType, ToACAction};
use crate::access::{ObjectType, ToACAction};
use async_trait::async_trait;
use crate::biz::casbin::metrics::AccessControlMetrics;
use crate::metrics::AccessControlMetrics;
use casbin::Adapter;
use casbin::Filter;
use casbin::Model;

View File

@ -1,9 +1,9 @@
use crate::biz::casbin::access_control::{
use crate::access::{
load_group_policies, ActionVariant, ObjectType, ToACAction, POLICY_FIELD_INDEX_OBJECT,
POLICY_FIELD_INDEX_SUBJECT,
};
use crate::biz::casbin::metrics::MetricsCalState;
use crate::biz::casbin::request::{GroupPolicyRequest, PolicyRequest, WorkspacePolicyRequest};
use crate::metrics::MetricsCalState;
use crate::request::{GroupPolicyRequest, PolicyRequest, WorkspacePolicyRequest};
use anyhow::anyhow;
use app_error::AppError;
use async_trait::async_trait;
@ -223,8 +223,8 @@ impl EnforcerGroup for NoEnforceGroup {
#[cfg(test)]
mod tests {
use crate::biz::casbin::access_control::{casbin_model, Action, ActionVariant, ObjectType};
use crate::biz::casbin::enforcer::{AFEnforcer, EnforcerGroup, NoEnforceGroup};
use crate::access::{casbin_model, Action, ActionVariant, ObjectType};
use crate::enforcer::{AFEnforcer, EnforcerGroup, NoEnforceGroup};
use async_trait::async_trait;
use casbin::{CoreApi, MemoryAdapter};
use database_entity::dto::{AFAccessLevel, AFRole};

View File

@ -0,0 +1,5 @@
pub mod access;
mod adapter;
pub mod enforcer;
pub mod metrics;
mod request;

View File

@ -2,7 +2,7 @@ use prometheus_client::metrics::gauge::Gauge;
use std::sync::atomic::{AtomicI64, Ordering};
use std::sync::Arc;
use crate::biz::casbin::enforcer::ENFORCER_METRICS_TICK_INTERVAL;
use crate::enforcer::ENFORCER_METRICS_TICK_INTERVAL;
use prometheus_client::registry::Registry;
use tokio::time::interval;

View File

@ -1,4 +1,4 @@
use crate::biz::casbin::access_control::{ActionVariant, ObjectType, ToACAction};
use crate::access::{ActionVariant, ObjectType, ToACAction};
pub struct GroupPolicyRequest<'a> {
pub guid: &'a str,

View File

@ -4,9 +4,11 @@ use crate::api::file_storage::file_storage_scope;
use crate::api::user::user_scope;
use crate::api::workspace::{collab_scope, workspace_scope};
use crate::api::ws::ws_scope;
use crate::biz::casbin::access_control::{enable_access_control, AccessControl};
use access_control::access::{enable_access_control, AccessControl};
use crate::biz::casbin::RealtimeCollabAccessControlImpl;
use crate::biz::casbin::{
CollabAccessControlImpl, RealtimeCollabAccessControlImpl, WorkspaceAccessControlImpl,
};
use crate::biz::collab::access_control::{
CollabMiddlewareAccessControl, CollabStorageAccessControlImpl,
};
@ -213,8 +215,8 @@ pub async fn init_state(config: &Config, rt_cmd_tx: RTCommandSender) -> Result<A
);
let user_cache = UserCache::new(pg_pool.clone()).await;
let collab_access_control = access_control.new_collab_access_control();
let workspace_access_control = access_control.new_workspace_access_control();
let collab_access_control = CollabAccessControlImpl::new(access_control.clone());
let workspace_access_control = WorkspaceAccessControlImpl::new(access_control.clone());
let collab_cache = CollabCache::new(redis_client.clone(), pg_pool.clone());
let collab_storage_access_control = CollabStorageAccessControlImpl {

View File

@ -1,8 +1,6 @@
use crate::biz::casbin::access_control::ObjectType;
use crate::biz::casbin::access_control::{
enable_access_control, AccessControl, Action, ActionVariant,
};
use crate::biz::collab::access_control::CollabAccessControl;
use access_control::access::ObjectType;
use access_control::access::{enable_access_control, AccessControl, Action, ActionVariant};
use app_error::AppError;
use async_trait::async_trait;

View File

@ -1,10 +1,5 @@
pub mod access_control;
pub mod adapter;
mod collab_ac;
mod enforcer;
pub(crate) mod metrics;
pub mod pg_listen;
mod request;
mod workspace_ac;
pub use collab_ac::CollabAccessControlImpl;

View File

@ -1,4 +1,4 @@
use crate::biz::casbin::access_control::{AccessControl, ActionVariant, ObjectType};
use access_control::access::{AccessControl, ActionVariant, ObjectType};
use crate::biz::pg_listener::PostgresDBListener;
use database::pg_row::AFCollabMemberRow;

View File

@ -1,6 +1,6 @@
use crate::biz::casbin::access_control::ObjectType;
use crate::biz::casbin::access_control::{AccessControl, Action, ActionVariant};
use crate::biz::workspace::access_control::WorkspaceAccessControl;
use access_control::access::ObjectType;
use access_control::access::{AccessControl, Action, ActionVariant};
use app_error::AppError;
use async_trait::async_trait;
use database_entity::dto::{AFAccessLevel, AFRole};

View File

@ -1,7 +1,7 @@
use crate::api::workspace::COLLAB_PATTERN;
use crate::biz::casbin::access_control::Action;
use crate::biz::workspace::access_control::WorkspaceAccessControl;
use crate::middleware::access_control_mw::{AccessResource, MiddlewareAccessControl};
use access_control::access::Action;
use actix_router::{Path, ResourceDef, Url};
use actix_web::http::Method;
use app_error::AppError;

View File

@ -11,8 +11,8 @@ use std::collections::HashMap;
use crate::api::workspace::{
WORKSPACE_INVITE_PATTERN, WORKSPACE_MEMBER_PATTERN, WORKSPACE_PATTERN,
};
use crate::biz::casbin::access_control::Action;
use crate::state::UserCache;
use access_control::access::Action;
use actix_router::{Path, ResourceDef, Url};
use anyhow::anyhow;
use app_error::AppError;

View File

@ -1,7 +1,7 @@
use crate::api::workspace::{COLLAB_OBJECT_ID_PATH, WORKSPACE_ID_PATH};
use crate::biz::casbin::access_control::enable_access_control;
use crate::biz::user::auth::jwt::UserUuid;
use crate::state::AppState;
use access_control::access::enable_access_control;
use actix_router::{Path, Url};
use actix_service::{forward_ready, Service, Transform};
use actix_web::dev::{ResourceDef, ServiceRequest, ServiceResponse};

View File

@ -1,12 +1,12 @@
use crate::api::metrics::RequestMetrics;
use crate::biz::casbin::access_control::AccessControl;
use crate::biz::casbin::metrics::AccessControlMetrics;
use crate::biz::casbin::{CollabAccessControlImpl, WorkspaceAccessControlImpl};
use crate::biz::collab::cache::CollabCache;
use crate::biz::collab::metrics::CollabMetrics;
use crate::biz::collab::storage::CollabAccessControlStorage;
use crate::biz::pg_listener::PgListeners;
use crate::config::config::Config;
use access_control::access::AccessControl;
use access_control::metrics::AccessControlMetrics;
use app_error::AppError;
use collab_rt::CollabRealtimeMetrics;
use dashmap::DashMap;