diff --git a/server/lib/src/constants/entries.rs b/server/lib/src/constants/entries.rs index 03ebbd972..5f404ca44 100644 --- a/server/lib/src/constants/entries.rs +++ b/server/lib/src/constants/entries.rs @@ -1,8 +1,9 @@ //! Constant Entries for the IDM -use crate::prelude::{idm_builtin_admin_groups, AttrString}; +use crate::prelude::AttrString; use enum_iterator::Sequence; use std::fmt::Display; +use crate::constants::groups::idm_builtin_admin_groups; use crate::constants::uuids::*; use crate::entry::{Entry, EntryInit, EntryInitNew, EntryNew}; use crate::idm::account::Account; diff --git a/server/lib/src/server/access/delete.rs b/server/lib/src/server/access/delete.rs index 916cdb962..52fc319b3 100644 --- a/server/lib/src/server/access/delete.rs +++ b/server/lib/src/server/access/delete.rs @@ -162,14 +162,18 @@ fn protected_filter_entry(ident: &Identity, entry: &Arc) - if classes.contains(&EntryClass::SyncObject.into()) { // Block the mod security_access!("attempt to delete with protected class type"); - IResult::Denied - } else { - IResult::Ignore + return IResult::Denied; } - } else { - // Nothing to check. - IResult::Ignore + }; + + // Prevent deletion of entries that exist in the system controlled entry range. + if entry.get_uuid() <= UUID_ANONYMOUS { + security_access!("attempt to delete system builtin entry"); + return IResult::Denied; } + + // Checks exhausted, no more input from us + IResult::Ignore } } } diff --git a/server/lib/src/server/access/mod.rs b/server/lib/src/server/access/mod.rs index ec842ff56..70ae52fdd 100644 --- a/server/lib/src/server/access/mod.rs +++ b/server/lib/src/server/access/mod.rs @@ -3118,4 +3118,30 @@ mod tests { // Test reject delete test_acp_delete!(&de_b, vec![acp], &data_set, false); } + + #[test] + fn test_access_delete_protect_system_ranges() { + let ev1: EntryInitNew = BUILTIN_ACCOUNT_ANONYMOUS_V1.clone().into(); + let ev1 = ev1.into_sealed_committed(); + let r_set = vec![Arc::new(ev1)]; + + let de_account = DeleteEvent::new_impersonate_entry( + E_TEST_ACCOUNT_1.clone(), + filter_all!(f_eq( + Attribute::Name, + PartialValue::new_iname("testperson1") + )), + ); + + let acp = AccessControlDelete::from_raw( + "test_delete", + Uuid::new_v4(), + UUID_TEST_GROUP_1, + // To delete testperson + filter_valid!(f_eq(Attribute::Name, PartialValue::new_iname("anonymous"))), + ); + + // Test reject delete, can not delete due to system protection + test_acp_delete!(&de_account, vec![acp], &r_set, false); + } }