Skip to content

Commit

Permalink
249 2024 managed by syntax (kanidm#2359)
Browse files Browse the repository at this point in the history
Allows hierarchial entry management rules.
  • Loading branch information
Firstyear authored Dec 7, 2023
1 parent 340d414 commit 854b696
Show file tree
Hide file tree
Showing 14 changed files with 1,147 additions and 456 deletions.
1 change: 1 addition & 0 deletions proto/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ pub const ATTR_EMAIL_ALTERNATIVE: &str = "emailalternative";
pub const ATTR_EMAIL_PRIMARY: &str = "emailprimary";
pub const ATTR_EMAIL: &str = "email";
pub const ATTR_ENTRYDN: &str = "entrydn";
pub const ATTR_ENTRY_MANAGED_BY: &str = "entry_managed_by";
pub const ATTR_ENTRYUUID: &str = "entryuuid";
pub const ATTR_LDAP_KEYS: &str = "keys";
pub const ATTR_EXCLUDES: &str = "excludes";
Expand Down
353 changes: 192 additions & 161 deletions server/lib/src/constants/acp.rs

Large diffs are not rendered by default.

11 changes: 11 additions & 0 deletions server/lib/src/constants/entries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ pub enum Attribute {
EmailAlternative,
EmailPrimary,
EntryDn,
EntryManagedBy,
EntryUuid,
Es256PrivateKeyDer,
Excludes,
Expand Down Expand Up @@ -266,6 +267,7 @@ impl TryFrom<String> for Attribute {
ATTR_EMAIL_ALTERNATIVE => Attribute::EmailAlternative,
ATTR_EMAIL_PRIMARY => Attribute::EmailPrimary,
ATTR_ENTRYDN => Attribute::EntryDn,
ATTR_ENTRY_MANAGED_BY => Attribute::EntryManagedBy,
ATTR_ENTRYUUID => Attribute::EntryUuid,
ATTR_ES256_PRIVATE_KEY_DER => Attribute::Es256PrivateKeyDer,
ATTR_EXCLUDES => Attribute::Excludes,
Expand Down Expand Up @@ -425,6 +427,7 @@ impl From<Attribute> for &'static str {
Attribute::EmailAlternative => ATTR_EMAIL_ALTERNATIVE,
Attribute::EmailPrimary => ATTR_EMAIL_PRIMARY,
Attribute::EntryDn => ATTR_ENTRYDN,
Attribute::EntryManagedBy => ATTR_ENTRY_MANAGED_BY,
Attribute::EntryUuid => ATTR_ENTRYUUID,
Attribute::Es256PrivateKeyDer => ATTR_ES256_PRIVATE_KEY_DER,
Attribute::Excludes => ATTR_EXCLUDES,
Expand Down Expand Up @@ -570,7 +573,10 @@ pub enum EntryClass {
AccessControlDelete,
AccessControlModify,
AccessControlProfile,
AccessControlReceiverEntryManager,
AccessControlReceiverGroup,
AccessControlSearch,
AccessControlTargetScope,
Account,
AccountPolicy,
AttributeType,
Expand Down Expand Up @@ -611,7 +617,12 @@ impl From<EntryClass> for &'static str {
EntryClass::AccessControlDelete => "access_control_delete",
EntryClass::AccessControlModify => "access_control_modify",
EntryClass::AccessControlProfile => "access_control_profile",
EntryClass::AccessControlReceiverEntryManager => {
"access_control_receiver_entry_manager"
}
EntryClass::AccessControlReceiverGroup => "access_control_receiver_group",
EntryClass::AccessControlSearch => "access_control_search",
EntryClass::AccessControlTargetScope => "access_control_target_scope",
EntryClass::Account => "account",
EntryClass::AccountPolicy => "account_policy",
EntryClass::AttributeType => "attributetype",
Expand Down
7 changes: 7 additions & 0 deletions server/lib/src/constants/uuids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,13 @@ pub const UUID_SCHEMA_ATTR_UID: Uuid = uuid!("00000000-0000-0000-0000-ffff000001
pub const UUID_SCHEMA_ATTR_GECOS: Uuid = uuid!("00000000-0000-0000-0000-ffff00000151");
pub const UUID_SCHEMA_ATTR_WEBAUTHN_ATTESTATION_CA_LIST: Uuid =
uuid!("00000000-0000-0000-0000-ffff00000152");
pub const UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_GROUP: Uuid =
uuid!("00000000-0000-0000-0000-ffff00000153");
pub const UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_ENTRY_MANAGER: Uuid =
uuid!("00000000-0000-0000-0000-ffff00000154");
pub const UUID_SCHEMA_CLASS_ACCESS_CONTROL_TARGET_SCOPE: Uuid =
uuid!("00000000-0000-0000-0000-ffff00000155");
pub const UUID_SCHEMA_ATTR_ENTRY_MANAGED_BY: Uuid = uuid!("00000000-0000-0000-0000-ffff00000156");

// System and domain infos
// I'd like to strongly criticise william of the past for making poor choices about these allocations.
Expand Down
8 changes: 8 additions & 0 deletions server/lib/src/plugins/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,14 @@ mod tests {
Attribute::Class,
EntryClass::AccessControlProfile.to_value()
),
(
Attribute::Class,
EntryClass::AccessControlTargetScope.to_value()
),
(
Attribute::Class,
EntryClass::AccessControlReceiverGroup.to_value()
),
(Attribute::Class, EntryClass::AccessControlModify.to_value()),
(Attribute::Class, EntryClass::AccessControlCreate.to_value()),
(Attribute::Class, EntryClass::AccessControlDelete.to_value()),
Expand Down
8 changes: 8 additions & 0 deletions server/lib/src/plugins/protected.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,14 @@ mod tests {
Attribute::Class,
EntryClass::AccessControlProfile.to_value()
),
(
Attribute::Class,
EntryClass::AccessControlTargetScope.to_value()
),
(
Attribute::Class,
EntryClass::AccessControlReceiverGroup.to_value()
),
(Attribute::Class, EntryClass::AccessControlModify.to_value()),
(Attribute::Class, EntryClass::AccessControlCreate.to_value()),
(Attribute::Class, EntryClass::AccessControlDelete.to_value()),
Expand Down
45 changes: 45 additions & 0 deletions server/lib/src/plugins/refint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1208,4 +1208,49 @@ mod tests {

assert!(server_txn.commit().is_ok());
}

#[qs_test]
async fn test_entry_managed_by_references(server: &QueryServer) {
let curtime = duration_from_epoch_now();
let mut server_txn = server.write(curtime).await;

let manages_uuid = Uuid::new_v4();
let e_manages: Entry<EntryInit, EntryNew> = entry_init!(
(Attribute::Class, EntryClass::Group.to_value()),
(Attribute::Name, Value::new_iname("entry_manages")),
(Attribute::Uuid, Value::Uuid(manages_uuid))
);

let group_uuid = Uuid::new_v4();
let e_group: Entry<EntryInit, EntryNew> = entry_init!(
(Attribute::Class, EntryClass::Group.to_value()),
(Attribute::Name, Value::new_iname("entry_managed_by")),
(Attribute::Uuid, Value::Uuid(group_uuid)),
(Attribute::EntryManagedBy, Value::Refer(manages_uuid))
);

let ce = CreateEvent::new_internal(vec![e_manages, e_group]);
assert!(server_txn.create(&ce).is_ok());

let group = server_txn
.internal_search_uuid(group_uuid)
.expect("Failed to access group");

let entry_managed_by = group
.get_ava_single_refer(Attribute::EntryManagedBy)
.expect("No entry managed by");

assert_eq!(entry_managed_by, manages_uuid);

// It's valid to delete this, since entryManagedBy is may not must.
assert!(server_txn.internal_delete_uuid(manages_uuid).is_ok());

let group = server_txn
.internal_search_uuid(group_uuid)
.expect("Failed to access group");

assert!(group.get_ava_refer(Attribute::EntryManagedBy).is_none());

assert!(server_txn.commit().is_ok());
}
}
105 changes: 77 additions & 28 deletions server/lib/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1248,7 +1248,7 @@ impl<'a> SchemaWriteTransaction<'a> {
description: String::from(
"The group that receives this access control to allow access",
),
multivalue: false,
multivalue: true,
unique: false,
phantom: false,
sync_allowed: false,
Expand All @@ -1264,7 +1264,7 @@ impl<'a> SchemaWriteTransaction<'a> {
name: Attribute::AcpTargetScope.into(),
uuid: UUID_SCHEMA_ATTR_ACP_TARGETSCOPE,
description: String::from(
"The effective targets of the ACP, IE what will be acted upon.",
"The effective targets of the ACP, e.g. what will be acted upon.",
),
multivalue: false,
unique: false,
Expand Down Expand Up @@ -1374,6 +1374,23 @@ impl<'a> SchemaWriteTransaction<'a> {
syntax: SyntaxType::Utf8StringInsensitive,
},
);
self.attributes.insert(
Attribute::EntryManagedBy.into(),
SchemaAttribute {
name: Attribute::EntryManagedBy.into(),
uuid: UUID_SCHEMA_ATTR_ENTRY_MANAGED_BY,
description: String::from(
"A reference to a group that has access to manage the content of this entry.",
),
multivalue: false,
unique: false,
phantom: false,
sync_allowed: false,
replicated: true,
index: vec![IndexType::Equality],
syntax: SyntaxType::ReferenceUuid,
},
);
// MO/Member
self.attributes.insert(
Attribute::MemberOf.into(),
Expand Down Expand Up @@ -1886,7 +1903,10 @@ impl<'a> SchemaWriteTransaction<'a> {
name: EntryClass::Object.into(),
uuid: UUID_SCHEMA_CLASS_OBJECT,
description: String::from("A system created class that all objects must contain"),
systemmay: vec![Attribute::Description.into()],
systemmay: vec![
Attribute::Description.into(),
Attribute::EntryManagedBy.into(),
],
systemmust: vec![
Attribute::Class.into(),
Attribute::Uuid.into(),
Expand Down Expand Up @@ -1966,31 +1986,6 @@ impl<'a> SchemaWriteTransaction<'a> {
},
);
// ACP
self.classes.insert(
EntryClass::AccessControlProfile.into(),
SchemaClass {
name: EntryClass::AccessControlProfile.into(),
uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_PROFILE,
description: String::from("System Access Control Profile Class"),
systemmay: vec![
Attribute::AcpEnable.into(),
Attribute::Description.into(),
Attribute::AcpReceiver.into(),
],
systemmust: vec![
Attribute::AcpReceiverGroup.into(),
Attribute::AcpTargetScope.into(),
Attribute::Name.into(),
],
systemsupplements: vec![
EntryClass::AccessControlSearch.into(),
EntryClass::AccessControlDelete.into(),
EntryClass::AccessControlModify.into(),
EntryClass::AccessControlCreate.into(),
],
..Default::default()
},
);
self.classes.insert(
EntryClass::AccessControlSearch.into(),
SchemaClass {
Expand Down Expand Up @@ -2037,6 +2032,60 @@ impl<'a> SchemaWriteTransaction<'a> {
..Default::default()
},
);
self.classes.insert(
EntryClass::AccessControlProfile.into(),
SchemaClass {
name: EntryClass::AccessControlProfile.into(),
uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_PROFILE,
description: String::from("System Access Control Profile Class"),
systemmay: vec![Attribute::AcpEnable.into(), Attribute::Description.into()],
systemmust: vec![Attribute::Name.into()],
systemsupplements: vec![
EntryClass::AccessControlSearch.into(),
EntryClass::AccessControlDelete.into(),
EntryClass::AccessControlModify.into(),
EntryClass::AccessControlCreate.into(),
],
..Default::default()
},
);
self.classes.insert(
EntryClass::AccessControlReceiverEntryManager.into(),
SchemaClass {
name: EntryClass::AccessControlReceiverEntryManager.into(),
uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_ENTRY_MANAGER,
description: String::from("System Access Control Profile Receiver - Entry Manager"),
systemexcludes: vec![EntryClass::AccessControlReceiverGroup.into()],
systemsupplements: vec![EntryClass::AccessControlProfile.into()],
..Default::default()
},
);
self.classes.insert(
EntryClass::AccessControlReceiverGroup.into(),
SchemaClass {
name: EntryClass::AccessControlReceiverGroup.into(),
uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_GROUP,
description: String::from("System Access Control Profile Receiver - Group"),
systemmay: vec![Attribute::AcpReceiver.into()],
systemmust: vec![Attribute::AcpReceiverGroup.into()],
systemsupplements: vec![EntryClass::AccessControlProfile.into()],
systemexcludes: vec![EntryClass::AccessControlReceiverEntryManager.into()],
..Default::default()
},
);
self.classes.insert(
EntryClass::AccessControlTargetScope.into(),
SchemaClass {
name: EntryClass::AccessControlTargetScope.into(),
uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_TARGET_SCOPE,
description: String::from("System Access Control Profile Target - Scope"),
systemmust: vec![Attribute::AcpTargetScope.into()],
systemsupplements: vec![EntryClass::AccessControlProfile.into()],
..Default::default()
},
);

// System attrs
self.classes.insert(
EntryClass::System.into(),
SchemaClass {
Expand Down
Loading

0 comments on commit 854b696

Please sign in to comment.