diff --git a/crates/keystone/src/api/v3/role_assignment/project/user/role/revoke.rs b/crates/keystone/src/api/v3/role_assignment/project/user/role/revoke.rs index a73c27c4..0ff8ecec 100644 --- a/crates/keystone/src/api/v3/role_assignment/project/user/role/revoke.rs +++ b/crates/keystone/src/api/v3/role_assignment/project/user/role/revoke.rs @@ -151,7 +151,6 @@ mod tests { use crate::identity::{MockIdentityProvider, types::*}; use crate::provider::Provider; use crate::resource::{MockResourceProvider, types::Project}; - #[tokio::test] #[traced_test] async fn test_revoke_success() { diff --git a/crates/keystone/src/assignment/backend.rs b/crates/keystone/src/assignment/backend.rs index aec134d5..306aefc5 100644 --- a/crates/keystone/src/assignment/backend.rs +++ b/crates/keystone/src/assignment/backend.rs @@ -91,6 +91,6 @@ pub trait AssignmentBackend: Send + Sync { async fn revoke_grant( &self, state: &ServiceState, - params: Assignment, + params: &Assignment, ) -> Result<(), AssignmentProviderError>; } diff --git a/crates/keystone/src/assignment/backend/sql.rs b/crates/keystone/src/assignment/backend/sql.rs index ed984434..13ba6827 100644 --- a/crates/keystone/src/assignment/backend/sql.rs +++ b/crates/keystone/src/assignment/backend/sql.rs @@ -136,7 +136,7 @@ impl AssignmentBackend for SqlBackend { async fn revoke_grant( &self, state: &ServiceState, - grant: Assignment, + grant: &Assignment, ) -> Result<(), AssignmentProviderError> { Ok(assignment::delete(&state.db, grant).await?) } diff --git a/crates/keystone/src/assignment/backend/sql/assignment/delete.rs b/crates/keystone/src/assignment/backend/sql/assignment/delete.rs index 8e3a87b8..0a3d436c 100644 --- a/crates/keystone/src/assignment/backend/sql/assignment/delete.rs +++ b/crates/keystone/src/assignment/backend/sql/assignment/delete.rs @@ -24,7 +24,7 @@ use crate::error::DbContextExt; /// Delete assignment grant. pub async fn delete( db: &DatabaseConnection, - grant: Assignment, + grant: &Assignment, ) -> Result<(), AssignmentDatabaseError> { let rows_affected = match &grant.r#type { AssignmentType::GroupDomain @@ -96,7 +96,7 @@ mod tests { implied_via: None, }; - delete(&db, grant).await.unwrap(); + delete(&db, &grant).await.unwrap(); // Update expected SQL to match delete_by_id order assert_eq!( @@ -134,7 +134,7 @@ mod tests { implied_via: None, }; - delete(&db, grant).await.unwrap(); + delete(&db, &grant).await.unwrap(); assert_eq!( db.into_transaction_log(), @@ -171,7 +171,7 @@ mod tests { implied_via: None, }; - delete(&db, grant).await.unwrap(); + delete(&db, &grant).await.unwrap(); assert_eq!( db.into_transaction_log(), @@ -208,7 +208,7 @@ mod tests { implied_via: None, }; - delete(&db, grant).await.unwrap(); + delete(&db, &grant).await.unwrap(); assert_eq!( db.into_transaction_log(), @@ -245,7 +245,7 @@ mod tests { implied_via: None, }; - delete(&db, grant).await.unwrap(); + delete(&db, &grant).await.unwrap(); assert_eq!( db.into_transaction_log(), @@ -282,7 +282,7 @@ mod tests { implied_via: None, }; - delete(&db, grant).await.unwrap(); + delete(&db, &grant).await.unwrap(); assert_eq!( db.into_transaction_log(), @@ -319,7 +319,7 @@ mod tests { implied_via: None, }; - let result = delete(&db, grant).await; + let result = delete(&db, &grant).await; assert!(result.is_err()); diff --git a/crates/keystone/src/assignment/error.rs b/crates/keystone/src/assignment/error.rs index b17efce7..4a66ef39 100644 --- a/crates/keystone/src/assignment/error.rs +++ b/crates/keystone/src/assignment/error.rs @@ -17,6 +17,7 @@ use thiserror::Error; use crate::assignment::backend::error::*; use crate::identity::error::IdentityProviderError; use crate::resource::error::ResourceProviderError; +use crate::revoke::error::RevokeProviderError; /// Assignment provider error. #[derive(Error, Debug)] @@ -47,6 +48,13 @@ pub enum AssignmentProviderError { source: ResourceProviderError, }, + /// Revoke provider error. + #[error(transparent)] + RevokeProvider { + #[from] + source: RevokeProviderError, + }, + /// Role not found. #[error("role {0} not found")] RoleNotFound(String), diff --git a/crates/keystone/src/assignment/mod.rs b/crates/keystone/src/assignment/mod.rs index 87f27b28..43c5e13a 100644 --- a/crates/keystone/src/assignment/mod.rs +++ b/crates/keystone/src/assignment/mod.rs @@ -64,6 +64,7 @@ use crate::identity::IdentityApi; use crate::keystone::ServiceState; use crate::plugin_manager::PluginManager; use crate::resource::ResourceApi; +use crate::revoke::{RevokeApi, types::RevocationEventCreate}; #[cfg(test)] pub use mock::MockAssignmentProvider; @@ -238,6 +239,52 @@ impl AssignmentApi for AssignmentProvider { state: &ServiceState, grant: Assignment, ) -> Result<(), AssignmentProviderError> { - self.backend_driver.revoke_grant(state, grant).await + // Call backend with reference (no move) + self.backend_driver.revoke_grant(state, &grant).await?; + + // Determine user_id or group_id + let user_id = match &grant.r#type { + AssignmentType::UserDomain + | AssignmentType::UserProject + | AssignmentType::UserSystem => Some(grant.actor_id.clone()), + + AssignmentType::GroupDomain + | AssignmentType::GroupProject + | AssignmentType::GroupSystem => None, + }; + + // Determine project_id or domain_id + let (project_id, domain_id) = match &grant.r#type { + AssignmentType::UserProject | AssignmentType::GroupProject => { + (Some(grant.target_id.clone()), None) + } + AssignmentType::UserDomain | AssignmentType::GroupDomain => { + (None, Some(grant.target_id.clone())) + } + AssignmentType::UserSystem | AssignmentType::GroupSystem => (None, None), + }; + + let revocation_event = RevocationEventCreate { + domain_id, + project_id, + user_id, + role_id: Some(grant.role_id.clone()), + trust_id: None, + consumer_id: None, + access_token_id: None, + issued_before: chrono::Utc::now(), + expires_at: None, + audit_id: None, + audit_chain_id: None, + revoked_at: chrono::Utc::now(), + }; + + state + .provider + .get_revoke_provider() + .create_revocation_event(state, revocation_event) + .await?; + + Ok(()) } }