diff --git a/Cargo.lock b/Cargo.lock index cdc15fde..56f6e4da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -197,7 +197,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -208,7 +208,7 @@ checksum = "d556ec1359574147ec0c4fc5eb525f3f23263a592b1a9c07e0a75b427de55c97" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -289,7 +289,7 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -321,9 +321,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "bb97d56060ee67d285efb8001fec9d2a4c710c32efd2e14b5cbb5ba71930fc2d" [[package]] name = "bcrypt" @@ -412,7 +412,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -559,9 +559,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.31" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" +checksum = "6088f3ae8c3608d19260cd7445411865a485688711b78b5be70d78cd96136f83" dependencies = [ "clap_builder", "clap_derive", @@ -569,9 +569,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.31" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" +checksum = "22a7ef7f676155edfb82daa97f99441f3ebf4a58d5e32f295a56259f1b6facc8" dependencies = [ "anstream", "anstyle", @@ -581,14 +581,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.28" +version = "4.5.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" +checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -841,7 +841,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -852,7 +852,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -884,7 +884,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -905,7 +905,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -915,7 +915,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -938,7 +938,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -1345,9 +1345,9 @@ dependencies = [ [[package]] name = "http" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea" +checksum = "0a761d192fbf18bdef69f5ceedd0d1333afcbda0ee23840373b8317570d23c65" dependencies = [ "bytes", "fnv", @@ -1366,12 +1366,12 @@ dependencies = [ [[package]] name = "http-body-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "futures-util", + "futures-core", "http", "http-body", "pin-project-lite", @@ -1562,7 +1562,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -1600,9 +1600,9 @@ checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" [[package]] name = "indexmap" -version = "2.7.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" +checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -1617,7 +1617,7 @@ checksum = "6c38228f24186d9cc68c729accb4d413be9eaed6ad07ff79e0270d9e56f3de13" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -1702,9 +1702,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.170" +version = "0.2.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" +checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" [[package]] name = "libm" @@ -1846,7 +1846,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -1858,7 +1858,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -1945,9 +1945,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.3" +version = "1.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" +checksum = "cde51589ab56b20a6f686b2c68f7a0bd6add753d697abf720d63f8db3ab7b1ad" [[package]] name = "oorandom" @@ -1978,7 +1978,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -2073,7 +2073,7 @@ dependencies = [ "proc-macro2", "proc-macro2-diagnostics", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -2175,7 +2175,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -2273,9 +2273,9 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.20" +version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" dependencies = [ "zerocopy", ] @@ -2334,7 +2334,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -2354,7 +2354,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", "version_check", "yansi", ] @@ -2583,7 +2583,7 @@ dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.99", + "syn 2.0.100", "walkdir", ] @@ -2632,9 +2632,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dade4812df5c384711475be5fcd8c162555352945401aed22a35bffeab61f657" +checksum = "f7178faa4b75a30e269c71e61c353ce2748cf3d76f0c44c393f4e60abf49b825" dependencies = [ "bitflags", "errno", @@ -2680,7 +2680,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -2722,7 +2722,7 @@ dependencies = [ "proc-macro2", "quote", "sea-bae", - "syn 2.0.99", + "syn 2.0.100", "unicode-ident", ] @@ -2790,7 +2790,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -3012,7 +3012,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -3035,7 +3035,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.99", + "syn 2.0.100", "tempfile", "tokio", "url", @@ -3211,9 +3211,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.99" +version = "2.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" +checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" dependencies = [ "proc-macro2", "quote", @@ -3234,7 +3234,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -3289,7 +3289,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -3300,7 +3300,7 @@ checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -3413,7 +3413,7 @@ checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -3544,7 +3544,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -3712,7 +3712,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -3820,7 +3820,7 @@ dependencies = [ "log", "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", "wasm-bindgen-shared", ] @@ -3842,7 +3842,7 @@ checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4146,29 +4146,28 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", "synstructure", ] [[package]] name = "zerocopy" -version = "0.7.35" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6" dependencies = [ - "byteorder", "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.35" +version = "0.8.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -4188,7 +4187,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", "synstructure", ] @@ -4209,7 +4208,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] @@ -4231,7 +4230,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.99", + "syn 2.0.100", ] [[package]] diff --git a/src/api/v3/auth/token/common.rs b/src/api/v3/auth/token/common.rs index 66f086fc..976e7e5d 100644 --- a/src/api/v3/auth/token/common.rs +++ b/src/api/v3/auth/token/common.rs @@ -14,6 +14,9 @@ use crate::api::error::{KeystoneApiError, TokenError}; use crate::api::v3::auth::token::types::{ProjectBuilder, Token, TokenBuilder, UserBuilder}; +use crate::api::v3::role::types::Role; +use crate::assignment::AssignmentApi; +use crate::assignment::types::RoleAssignmentListParametersBuilder; use crate::identity::IdentityApi; use crate::keystone::ServiceState; use crate::resource::ResourceApi; @@ -52,7 +55,7 @@ impl Token { })?; let mut user_response: UserBuilder = UserBuilder::default(); - user_response.id(user.id); + user_response.id(user.id.clone()); user_response.name(user.name); user_response.password_expires_at(user.password_expires_at); user_response.domain(user_domain.clone()); @@ -110,6 +113,29 @@ impl Token { project_response.domain(project_domain.clone().into()); } response.project(project_response.build().map_err(TokenError::from)?); + + let token_roles = state + .provider + .get_assignment_provider() + .list_role_assignments( + &state.db, + &state.provider, + &RoleAssignmentListParametersBuilder::default() + .user_id(user.id) + .project_id(&token.project_id) + .build()?, + ) + .await?; + response.roles( + token_roles + .into_iter() + .map(|x| Role { + id: x.role_id.clone(), + name: x.role_name.clone().unwrap_or_default(), + ..Default::default() + }) + .collect::>(), + ); } ProviderToken::ApplicationCredential(_token) => { todo!(); @@ -125,7 +151,11 @@ mod tests { use std::sync::Arc; use crate::api::v3::auth::token::types::Token; - use crate::assignment::MockAssignmentProvider; + use crate::api::v3::role::types::Role; + use crate::assignment::{ + MockAssignmentProvider, + types::{Assignment, AssignmentType, RoleAssignmentListParameters}, + }; use crate::config::Config; use crate::identity::{MockIdentityProvider, types::User}; use crate::keystone::Service; @@ -283,7 +313,19 @@ mod tests { })) }); let token_mock = MockTokenProvider::default(); - let assignment_mock = MockAssignmentProvider::default(); + let mut assignment_mock = MockAssignmentProvider::default(); + assignment_mock.expect_list_role_assignments().returning( + |_, _, q: &RoleAssignmentListParameters| { + Ok(vec![Assignment { + role_id: "rid".into(), + role_name: Some("role_name".into()), + actor_id: q.user_id.clone().unwrap(), + target_id: q.project_id.clone().unwrap(), + r#type: AssignmentType::UserProject, + inherited: false, + }]) + }, + ); let provider = ProviderBuilder::default() .config(config.clone()) .assignment(assignment_mock) @@ -312,5 +354,13 @@ mod tests { assert_eq!("project_domain_id", project.domain.id); assert_eq!("project_id", project.id); assert!(api_token.domain.is_none()); + assert_eq!( + api_token.roles, + Some(vec![Role { + id: "rid".into(), + name: "role_name".into(), + ..Default::default() + }]) + ); } } diff --git a/src/api/v3/auth/token/types.rs b/src/api/v3/auth/token/types.rs index 92c5a2b2..17cc2031 100644 --- a/src/api/v3/auth/token/types.rs +++ b/src/api/v3/auth/token/types.rs @@ -22,6 +22,7 @@ use derive_builder::Builder; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; +use crate::api::v3::role::types::Role; use crate::resource::types as resource_provider_types; /// Authorization token @@ -65,6 +66,11 @@ pub struct Token { #[serde(skip_serializing_if = "Option::is_none")] #[builder(default)] pub domain: Option, + + /// A list of role objects + #[serde(skip_serializing_if = "Option::is_none")] + #[builder(default)] + pub roles: Option>, } #[derive(Builder, Clone, Debug, Default, Deserialize, PartialEq, Serialize, ToSchema)] diff --git a/src/api/v3/role/mod.rs b/src/api/v3/role/mod.rs index 6f69ddae..c038c9f2 100644 --- a/src/api/v3/role/mod.rs +++ b/src/api/v3/role/mod.rs @@ -24,7 +24,7 @@ use crate::assignment::AssignmentApi; use crate::keystone::ServiceState; use types::{Role, RoleList, RoleListParameters, RoleResponse}; -mod types; +pub mod types; pub(super) fn openapi_router() -> OpenApiRouter { OpenApiRouter::new() diff --git a/src/api/v3/role_assignment/mod.rs b/src/api/v3/role_assignment/mod.rs index f03dec84..8441be26 100644 --- a/src/api/v3/role_assignment/mod.rs +++ b/src/api/v3/role_assignment/mod.rs @@ -129,6 +129,7 @@ mod tests { .returning(|_, _, _| { Ok(vec![Assignment { role_id: "role".into(), + role_name: Some("rn".into()), actor_id: "actor".into(), target_id: "target".into(), r#type: AssignmentType::UserProject, @@ -160,7 +161,10 @@ mod tests { let res: ApiAssignmentList = serde_json::from_slice(&body).unwrap(); assert_eq!( vec![ApiAssignment { - role: Role { id: "role".into() }, + role: Role { + id: "role".into(), + name: Some("rn".into()) + }, user: Some(User { id: "actor".into() }), scope: Scope::Project(Project { id: "target".into() @@ -189,6 +193,7 @@ mod tests { .returning(|_, _, _| { Ok(vec![Assignment { role_id: "role".into(), + role_name: None, actor_id: "actor".into(), target_id: "target".into(), r#type: AssignmentType::UserProject, @@ -211,6 +216,7 @@ mod tests { .returning(|_, _, _| { Ok(vec![Assignment { role_id: "role".into(), + role_name: None, actor_id: "actor".into(), target_id: "target".into(), r#type: AssignmentType::UserProject, @@ -232,6 +238,7 @@ mod tests { .returning(|_, _, _| { Ok(vec![Assignment { role_id: "role".into(), + role_name: None, actor_id: "actor".into(), target_id: "target".into(), r#type: AssignmentType::UserProject, diff --git a/src/api/v3/role_assignment/types.rs b/src/api/v3/role_assignment/types.rs index 6af0c7df..c30bcf7e 100644 --- a/src/api/v3/role_assignment/types.rs +++ b/src/api/v3/role_assignment/types.rs @@ -41,6 +41,7 @@ pub struct Assignment { #[derive(Builder, Clone, Debug, Deserialize, PartialEq, Serialize, ToSchema)] pub struct Role { pub id: String, + pub name: Option, } #[derive(Builder, Clone, Debug, Deserialize, PartialEq, Serialize, ToSchema)] @@ -75,7 +76,10 @@ impl TryFrom for Assignment { fn try_from(value: types::Assignment) -> Result { let mut builder = AssignmentBuilder::default(); - builder.role(Role { id: value.role_id }); + builder.role(Role { + id: value.role_id, + name: value.role_name, + }); match value.r#type { types::AssignmentType::GroupDomain => { builder.group(Group { @@ -207,7 +211,10 @@ mod tests { fn test_assignment_conversion() { assert_eq!( Assignment { - role: Role { id: "role".into() }, + role: Role { + id: "role".into(), + name: Some("role_name".into()) + }, user: Some(User { id: "actor".into() }), scope: Scope::Project(Project { id: "target".into() @@ -216,6 +223,7 @@ mod tests { }, Assignment::try_from(types::Assignment { role_id: "role".into(), + role_name: Some("role_name".into()), actor_id: "actor".into(), target_id: "target".into(), r#type: types::AssignmentType::UserProject, @@ -225,7 +233,10 @@ mod tests { ); assert_eq!( Assignment { - role: Role { id: "role".into() }, + role: Role { + id: "role".into(), + name: None + }, user: Some(User { id: "actor".into() }), scope: Scope::Domain(Domain { id: "target".into() @@ -234,6 +245,7 @@ mod tests { }, Assignment::try_from(types::Assignment { role_id: "role".into(), + role_name: None, actor_id: "actor".into(), target_id: "target".into(), r#type: types::AssignmentType::UserDomain, @@ -243,7 +255,10 @@ mod tests { ); assert_eq!( Assignment { - role: Role { id: "role".into() }, + role: Role { + id: "role".into(), + name: None + }, group: Some(Group { id: "actor".into() }), scope: Scope::Project(Project { id: "target".into() @@ -252,6 +267,7 @@ mod tests { }, Assignment::try_from(types::Assignment { role_id: "role".into(), + role_name: None, actor_id: "actor".into(), target_id: "target".into(), r#type: types::AssignmentType::GroupProject, @@ -261,7 +277,10 @@ mod tests { ); assert_eq!( Assignment { - role: Role { id: "role".into() }, + role: Role { + id: "role".into(), + name: None + }, group: Some(Group { id: "actor".into() }), scope: Scope::Domain(Domain { id: "target".into() @@ -270,6 +289,7 @@ mod tests { }, Assignment::try_from(types::Assignment { role_id: "role".into(), + role_name: None, actor_id: "actor".into(), target_id: "target".into(), r#type: types::AssignmentType::GroupDomain, diff --git a/src/assignment/backends/sql/assignment.rs b/src/assignment/backends/sql/assignment.rs index 6293d99e..c27b860c 100644 --- a/src/assignment/backends/sql/assignment.rs +++ b/src/assignment/backends/sql/assignment.rs @@ -20,7 +20,9 @@ use crate::assignment::backends::error::AssignmentDatabaseError; use crate::assignment::types::*; use crate::config::Config; use crate::db::entity::{ - assignment as db_assignment, prelude::Assignment as DbAssignment, + assignment as db_assignment, + prelude::{Assignment as DbAssignment, Role as DbRole}, + role as db_role, sea_orm_active_enums::Type as DbAssignmentType, }; @@ -88,7 +90,8 @@ pub async fn list_for_multiple_actors_and_targets( select = select.filter(cond); } - let db_entities: Vec = select.all(db).await?; + let db_entities: Vec<(db_assignment::Model, Option)> = + select.find_also_related(DbRole).all(db).await?; let results: Result, _> = db_entities .into_iter() .map(TryInto::::try_into) @@ -112,6 +115,26 @@ impl TryFrom for Assignment { } } +impl TryFrom<(db_assignment::Model, Option)> for Assignment { + type Error = AssignmentDatabaseError; + + fn try_from( + value: (db_assignment::Model, Option), + ) -> Result { + let mut builder = AssignmentBuilder::default(); + builder.role_id(value.0.role_id.clone()); + builder.actor_id(value.0.actor_id.clone()); + builder.target_id(value.0.target_id.clone()); + builder.inherited(value.0.inherited); + builder.r#type(value.0.r#type); + if let Some(val) = &value.1 { + builder.role_name(val.name.clone()); + } + + Ok(builder.build()?) + } +} + impl From for AssignmentType { fn from(value: DbAssignmentType) -> Self { match value { @@ -128,7 +151,7 @@ mod tests { use sea_orm::{DatabaseBackend, MockDatabase, Transaction}; use crate::config::Config; - use crate::db::entity::{assignment, sea_orm_active_enums}; + use crate::db::entity::{assignment, role, sea_orm_active_enums}; use super::*; @@ -142,6 +165,25 @@ mod tests { } } + fn get_role_assignment_with_role_mock(role_id: String) -> (assignment::Model, role::Model) { + ( + assignment::Model { + role_id: role_id.clone(), + actor_id: "actor".into(), + target_id: "target".into(), + r#type: sea_orm_active_enums::Type::UserProject, + inherited: false, + }, + role::Model { + id: role_id.clone(), + name: role_id.clone(), + extra: None, + domain_id: String::new(), + description: None, + }, + ) + } + #[tokio::test] async fn test_list() { // Create MockDatabase with mock query results @@ -158,6 +200,7 @@ mod tests { .unwrap(), vec![Assignment { role_id: "1".into(), + role_name: None, actor_id: "actor".into(), target_id: "target".into(), r#type: AssignmentType::UserProject, @@ -236,10 +279,10 @@ mod tests { async fn test_list_for_multuple_actor_targets() { // Create MockDatabase with mock query results let db = MockDatabase::new(DatabaseBackend::Postgres) - .append_query_results([vec![get_role_assignment_mock("1".into())]]) - .append_query_results([vec![get_role_assignment_mock("1".into())]]) - .append_query_results([vec![get_role_assignment_mock("1".into())]]) - .append_query_results([vec![get_role_assignment_mock("1".into())]]) + .append_query_results([vec![get_role_assignment_with_role_mock("1".into())]]) + .append_query_results([vec![get_role_assignment_with_role_mock("1".into())]]) + .append_query_results([vec![get_role_assignment_with_role_mock("1".into())]]) + .append_query_results([vec![get_role_assignment_with_role_mock("1".into())]]) .append_query_results([Vec::::new()]) .into_connection(); let config = Config::default(); @@ -261,6 +304,7 @@ mod tests { .unwrap(), vec![Assignment { role_id: "1".into(), + role_name: Some("1".into()), actor_id: "actor".into(), target_id: "target".into(), r#type: AssignmentType::UserProject, @@ -291,7 +335,7 @@ mod tests { .is_ok() ); - // empty actors and targets + //// empty actors and targets assert!( list_for_multiple_actors_and_targets( &config, @@ -306,7 +350,7 @@ mod tests { .is_ok() ); - // only mixed targets + //// only mixed targets assert!( list_for_multiple_actors_and_targets( &config, @@ -330,7 +374,7 @@ mod tests { .is_ok() ); - // only complex targets + //// only complex targets assert!( list_for_multiple_actors_and_targets( &config, @@ -360,7 +404,7 @@ mod tests { [ Transaction::from_sql_and_values( DatabaseBackend::Postgres, - r#"SELECT CAST("assignment"."type" AS text), "assignment"."actor_id", "assignment"."target_id", "assignment"."role_id", "assignment"."inherited" FROM "assignment" WHERE "assignment"."actor_id" IN ($1, $2, $3) AND "assignment"."role_id" = $4 AND "assignment"."target_id" = $5"#, + r#"SELECT CAST("assignment"."type" AS text) AS "A_type", "assignment"."actor_id" AS "A_actor_id", "assignment"."target_id" AS "A_target_id", "assignment"."role_id" AS "A_role_id", "assignment"."inherited" AS "A_inherited", "role"."id" AS "B_id", "role"."name" AS "B_name", "role"."extra" AS "B_extra", "role"."domain_id" AS "B_domain_id", "role"."description" AS "B_description" FROM "assignment" LEFT JOIN "role" ON "assignment"."role_id" = "role"."id" WHERE "assignment"."actor_id" IN ($1, $2, $3) AND "assignment"."role_id" = $4 AND "assignment"."target_id" = $5"#, [ "uid1".into(), "gid1".into(), @@ -371,7 +415,7 @@ mod tests { ), Transaction::from_sql_and_values( DatabaseBackend::Postgres, - r#"SELECT CAST("assignment"."type" AS text), "assignment"."actor_id", "assignment"."target_id", "assignment"."role_id", "assignment"."inherited" FROM "assignment" WHERE "assignment"."actor_id" IN ($1, $2, $3) AND ("assignment"."target_id" = $4 OR ("assignment"."target_id" = $5 AND "assignment"."inherited" = $6))"#, + r#"SELECT CAST("assignment"."type" AS text) AS "A_type", "assignment"."actor_id" AS "A_actor_id", "assignment"."target_id" AS "A_target_id", "assignment"."role_id" AS "A_role_id", "assignment"."inherited" AS "A_inherited", "role"."id" AS "B_id", "role"."name" AS "B_name", "role"."extra" AS "B_extra", "role"."domain_id" AS "B_domain_id", "role"."description" AS "B_description" FROM "assignment" LEFT JOIN "role" ON "assignment"."role_id" = "role"."id" WHERE "assignment"."actor_id" IN ($1, $2, $3) AND ("assignment"."target_id" = $4 OR ("assignment"."target_id" = $5 AND "assignment"."inherited" = $6))"#, [ "uid1".into(), "gid1".into(), @@ -383,17 +427,17 @@ mod tests { ), Transaction::from_sql_and_values( DatabaseBackend::Postgres, - r#"SELECT CAST("assignment"."type" AS text), "assignment"."actor_id", "assignment"."target_id", "assignment"."role_id", "assignment"."inherited" FROM "assignment""#, + r#"SELECT CAST("assignment"."type" AS text) AS "A_type", "assignment"."actor_id" AS "A_actor_id", "assignment"."target_id" AS "A_target_id", "assignment"."role_id" AS "A_role_id", "assignment"."inherited" AS "A_inherited", "role"."id" AS "B_id", "role"."name" AS "B_name", "role"."extra" AS "B_extra", "role"."domain_id" AS "B_domain_id", "role"."description" AS "B_description" FROM "assignment" LEFT JOIN "role" ON "assignment"."role_id" = "role"."id""#, [] ), Transaction::from_sql_and_values( DatabaseBackend::Postgres, - r#"SELECT CAST("assignment"."type" AS text), "assignment"."actor_id", "assignment"."target_id", "assignment"."role_id", "assignment"."inherited" FROM "assignment" WHERE "assignment"."target_id" = $1 OR ("assignment"."target_id" = $2 AND "assignment"."inherited" = $3)"#, + r#"SELECT CAST("assignment"."type" AS text) AS "A_type", "assignment"."actor_id" AS "A_actor_id", "assignment"."target_id" AS "A_target_id", "assignment"."role_id" AS "A_role_id", "assignment"."inherited" AS "A_inherited", "role"."id" AS "B_id", "role"."name" AS "B_name", "role"."extra" AS "B_extra", "role"."domain_id" AS "B_domain_id", "role"."description" AS "B_description" FROM "assignment" LEFT JOIN "role" ON "assignment"."role_id" = "role"."id" WHERE "assignment"."target_id" = $1 OR ("assignment"."target_id" = $2 AND "assignment"."inherited" = $3)"#, ["pid1".into(), "pid2".into(), true.into()] ), Transaction::from_sql_and_values( DatabaseBackend::Postgres, - r#"SELECT CAST("assignment"."type" AS text), "assignment"."actor_id", "assignment"."target_id", "assignment"."role_id", "assignment"."inherited" FROM "assignment" WHERE ("assignment"."target_id" = $1 AND "assignment"."inherited" = $2) OR ("assignment"."target_id" = $3 AND "assignment"."inherited" = $4)"#, + r#"SELECT CAST("assignment"."type" AS text) AS "A_type", "assignment"."actor_id" AS "A_actor_id", "assignment"."target_id" AS "A_target_id", "assignment"."role_id" AS "A_role_id", "assignment"."inherited" AS "A_inherited", "role"."id" AS "B_id", "role"."name" AS "B_name", "role"."extra" AS "B_extra", "role"."domain_id" AS "B_domain_id", "role"."description" AS "B_description" FROM "assignment" LEFT JOIN "role" ON "assignment"."role_id" = "role"."id" WHERE ("assignment"."target_id" = $1 AND "assignment"."inherited" = $2) OR ("assignment"."target_id" = $3 AND "assignment"."inherited" = $4)"#, ["pid1".into(), false.into(), "pid2".into(), true.into()] ), ] diff --git a/src/assignment/types/assignment.rs b/src/assignment/types/assignment.rs index a7914a2e..11dfbbd8 100644 --- a/src/assignment/types/assignment.rs +++ b/src/assignment/types/assignment.rs @@ -21,6 +21,9 @@ use serde::{Deserialize, Serialize}; pub struct Assignment { /// The role ID. pub role_id: String, + /// The role ID. + #[builder(default)] + pub role_name: Option, /// The actor id. pub actor_id: String, /// The target id. diff --git a/src/db/entity/assignment.rs b/src/db/entity/assignment.rs index 6060e735..0a105fdc 100644 --- a/src/db/entity/assignment.rs +++ b/src/db/entity/assignment.rs @@ -33,6 +33,19 @@ pub struct Model { } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] -pub enum Relation {} +pub enum Relation { + #[sea_orm( + belongs_to = "super::role::Entity", + from = "Column::RoleId", + to = "super::role::Column::Id" + )] + Role, +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::Role.def() + } +} impl ActiveModelBehavior for ActiveModel {} diff --git a/src/db/entity/role.rs b/src/db/entity/role.rs index 48e09d65..6cc0db3c 100644 --- a/src/db/entity/role.rs +++ b/src/db/entity/role.rs @@ -32,6 +32,8 @@ pub struct Model { pub enum Relation { #[sea_orm(has_many = "super::role_option::Entity")] RoleOption, + #[sea_orm(has_one = "super::assignment::Entity")] + RoleAssignment, } impl Related for Entity { @@ -40,4 +42,10 @@ impl Related for Entity { } } +impl Related for Entity { + fn to() -> RelationDef { + Relation::RoleAssignment.def() + } +} + impl ActiveModelBehavior for ActiveModel {}