mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Allow name write privileges to be withheld (#2773)
This commit is contained in:
parent
c1235a7186
commit
3723abb25d
|
@ -55,8 +55,9 @@ services.
|
||||||
|
|
||||||
## Default Permission Groups
|
## Default Permission Groups
|
||||||
|
|
||||||
Kanidm ships with default permission groups. You can use these to enable accounts to perform certain
|
Kanidm ships with default permission groups. You can use these to enable (or disable) accounts to
|
||||||
tasks within Kanidm as required.
|
performing certain actions or tasks within Kanidm as required by modifying the memberships of these
|
||||||
|
groups.
|
||||||
|
|
||||||
| group name | description |
|
| group name | description |
|
||||||
| ---------------------------- | ----------------------------------------------------------------------- |
|
| ---------------------------- | ----------------------------------------------------------------------- |
|
||||||
|
@ -68,7 +69,8 @@ tasks within Kanidm as required.
|
||||||
| `idm_people_admins` | create and modify persons |
|
| `idm_people_admins` | create and modify persons |
|
||||||
| `idm_people_on_boarding` | create (but not modify) persons. Intended for use with service accounts |
|
| `idm_people_on_boarding` | create (but not modify) persons. Intended for use with service accounts |
|
||||||
| `idm_people_pii_read` | allow read to personally identifying information |
|
| `idm_people_pii_read` | allow read to personally identifying information |
|
||||||
| `idm_people_self_write_mail` | allow self-modification of the mail attribute |
|
| `idm_people_self_mail_write` | allow self-modification of the mail attribute |
|
||||||
|
| `idm_people_self_name_write` | allow self-modification of the name related attributes |
|
||||||
| `idm_radius_servers` | read user radius secrets. Intended for use with service accounts |
|
| `idm_radius_servers` | read user radius secrets. Intended for use with service accounts |
|
||||||
| `idm_radius_service_admins` | create and reset user radius secrets, and allow users to access radius |
|
| `idm_radius_service_admins` | create and reset user radius secrets, and allow users to access radius |
|
||||||
| `idm_recycle_bin_admins` | modify and restore entries from the recycle bin |
|
| `idm_recycle_bin_admins` | modify and restore entries from the recycle bin |
|
||||||
|
|
|
@ -1143,7 +1143,7 @@ lazy_static! {
|
||||||
name: "idm_people_self_acp_write_mail",
|
name: "idm_people_self_acp_write_mail",
|
||||||
uuid: UUID_IDM_ACP_PEOPLE_SELF_WRITE_MAIL,
|
uuid: UUID_IDM_ACP_PEOPLE_SELF_WRITE_MAIL,
|
||||||
description: "Builtin IDM Control for self write of mail for people accounts.",
|
description: "Builtin IDM Control for self write of mail for people accounts.",
|
||||||
receiver: BuiltinAcpReceiver::Group(vec![UUID_IDM_PEOPLE_SELF_WRITE_MAIL]),
|
receiver: BuiltinAcpReceiver::Group(vec![UUID_IDM_PEOPLE_SELF_MAIL_WRITE]),
|
||||||
target: BuiltinAcpTarget::Filter(ProtoFilter::And(vec![
|
target: BuiltinAcpTarget::Filter(ProtoFilter::And(vec![
|
||||||
match_class_filter!(EntryClass::Person).clone(),
|
match_class_filter!(EntryClass::Person).clone(),
|
||||||
match_class_filter!(EntryClass::Account).clone(),
|
match_class_filter!(EntryClass::Account).clone(),
|
||||||
|
@ -1230,6 +1230,39 @@ lazy_static! {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref IDM_ACP_SELF_WRITE_DL7: BuiltinAcp = BuiltinAcp{
|
||||||
|
name: "idm_acp_self_write",
|
||||||
|
uuid: UUID_IDM_ACP_SELF_WRITE_V1,
|
||||||
|
classes: vec![
|
||||||
|
EntryClass::Object,
|
||||||
|
EntryClass::AccessControlProfile,
|
||||||
|
EntryClass::AccessControlModify,
|
||||||
|
],
|
||||||
|
description: "Builtin IDM Control for self write - required for people to update their own credentials in line with best practices.",
|
||||||
|
receiver: BuiltinAcpReceiver::Group ( vec![UUID_IDM_ALL_PERSONS] ),
|
||||||
|
target: BuiltinAcpTarget::Filter(ProtoFilter::SelfUuid),
|
||||||
|
modify_removed_attrs: vec![
|
||||||
|
Attribute::RadiusSecret,
|
||||||
|
Attribute::PrimaryCredential,
|
||||||
|
Attribute::SshPublicKey,
|
||||||
|
Attribute::UnixPassword,
|
||||||
|
Attribute::PassKeys,
|
||||||
|
Attribute::AttestedPasskeys,
|
||||||
|
Attribute::UserAuthTokenSession,
|
||||||
|
],
|
||||||
|
modify_present_attrs: vec![
|
||||||
|
Attribute::RadiusSecret,
|
||||||
|
Attribute::PrimaryCredential,
|
||||||
|
Attribute::SshPublicKey,
|
||||||
|
Attribute::UnixPassword,
|
||||||
|
Attribute::PassKeys,
|
||||||
|
Attribute::AttestedPasskeys,
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref IDM_ACP_SELF_NAME_WRITE_V1: BuiltinAcp = BuiltinAcp{
|
pub static ref IDM_ACP_SELF_NAME_WRITE_V1: BuiltinAcp = BuiltinAcp{
|
||||||
name: "idm_acp_self_name_write",
|
name: "idm_acp_self_name_write",
|
||||||
|
@ -1252,6 +1285,36 @@ lazy_static! {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref IDM_ACP_SELF_NAME_WRITE_DL7: BuiltinAcp = BuiltinAcp{
|
||||||
|
name: "idm_acp_self_name_write",
|
||||||
|
uuid: UUID_IDM_ACP_SELF_NAME_WRITE_V1,
|
||||||
|
classes: vec![
|
||||||
|
EntryClass::Object,
|
||||||
|
EntryClass::AccessControlProfile,
|
||||||
|
EntryClass::AccessControlModify,
|
||||||
|
],
|
||||||
|
description: "Builtin IDM Control for self write of name - required for people to update their own identities in line with best practices.",
|
||||||
|
receiver: BuiltinAcpReceiver::Group ( vec![UUID_IDM_PEOPLE_SELF_NAME_WRITE] ),
|
||||||
|
target: BuiltinAcpTarget::Filter(ProtoFilter::And(vec![
|
||||||
|
ProtoFilter::SelfUuid,
|
||||||
|
match_class_filter!(EntryClass::Person).clone(),
|
||||||
|
FILTER_ANDNOT_TOMBSTONE_OR_RECYCLED.clone(),
|
||||||
|
])),
|
||||||
|
modify_removed_attrs: vec![
|
||||||
|
Attribute::Name,
|
||||||
|
Attribute::DisplayName,
|
||||||
|
Attribute::LegalName,
|
||||||
|
],
|
||||||
|
modify_present_attrs: vec![
|
||||||
|
Attribute::Name,
|
||||||
|
Attribute::DisplayName,
|
||||||
|
Attribute::LegalName,
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref IDM_ACP_ACCOUNT_SELF_WRITE_V1: BuiltinAcp = BuiltinAcp {
|
pub static ref IDM_ACP_ACCOUNT_SELF_WRITE_V1: BuiltinAcp = BuiltinAcp {
|
||||||
name: "idm_acp_self_account_write",
|
name: "idm_acp_self_account_write",
|
||||||
|
|
|
@ -178,6 +178,18 @@ lazy_static! {
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Builtin IDM Group for granting people the ability to write to their own name attributes.
|
||||||
|
pub static ref BUILTIN_GROUP_PEOPLE_SELF_NAME_WRITE_DL7: BuiltinGroup = BuiltinGroup {
|
||||||
|
name: "idm_people_self_name_write",
|
||||||
|
description: "Builtin IDM Group denoting users that can write to their own name attributes.",
|
||||||
|
uuid: UUID_IDM_PEOPLE_SELF_NAME_WRITE,
|
||||||
|
entry_managed_by: Some(UUID_IDM_ADMINS),
|
||||||
|
members: vec![
|
||||||
|
UUID_IDM_ALL_PERSONS
|
||||||
|
],
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
pub static ref BUILTIN_GROUP_SERVICE_ACCOUNT_ADMINS: BuiltinGroup = BuiltinGroup {
|
pub static ref BUILTIN_GROUP_SERVICE_ACCOUNT_ADMINS: BuiltinGroup = BuiltinGroup {
|
||||||
name: "idm_service_account_admins",
|
name: "idm_service_account_admins",
|
||||||
description: "Builtin Service Account Administration Group.",
|
description: "Builtin Service Account Administration Group.",
|
||||||
|
@ -250,7 +262,16 @@ lazy_static! {
|
||||||
pub static ref IDM_PEOPLE_SELF_WRITE_MAIL_V1: BuiltinGroup = BuiltinGroup {
|
pub static ref IDM_PEOPLE_SELF_WRITE_MAIL_V1: BuiltinGroup = BuiltinGroup {
|
||||||
name: "idm_people_self_write_mail",
|
name: "idm_people_self_write_mail",
|
||||||
description: "Builtin IDM Group for people accounts to update their own mail.",
|
description: "Builtin IDM Group for people accounts to update their own mail.",
|
||||||
uuid: UUID_IDM_PEOPLE_SELF_WRITE_MAIL,
|
uuid: UUID_IDM_PEOPLE_SELF_MAIL_WRITE,
|
||||||
|
members: Vec::new(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Self-write of mail
|
||||||
|
pub static ref IDM_PEOPLE_SELF_MAIL_WRITE_DL7: BuiltinGroup = BuiltinGroup {
|
||||||
|
name: "idm_people_self_mail_write",
|
||||||
|
description: "Builtin IDM Group for people accounts to update their own mail.",
|
||||||
|
uuid: UUID_IDM_PEOPLE_SELF_MAIL_WRITE,
|
||||||
members: Vec::new(),
|
members: Vec::new(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -43,7 +43,7 @@ pub const UUID_IDM_HP_PEOPLE_EXTEND_PRIV: Uuid = uuid!("00000000-0000-0000-0000-
|
||||||
pub const UUID_IDM_RADIUS_SECRET_READ_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-000000000032");
|
pub const UUID_IDM_RADIUS_SECRET_READ_PRIV_V1: Uuid = uuid!("00000000-0000-0000-0000-000000000032");
|
||||||
pub const UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1: Uuid =
|
pub const UUID_IDM_RADIUS_SECRET_WRITE_PRIV_V1: Uuid =
|
||||||
uuid!("00000000-0000-0000-0000-000000000031");
|
uuid!("00000000-0000-0000-0000-000000000031");
|
||||||
pub const UUID_IDM_PEOPLE_SELF_WRITE_MAIL: Uuid = uuid!("00000000-0000-0000-0000-000000000033");
|
pub const UUID_IDM_PEOPLE_SELF_MAIL_WRITE: Uuid = uuid!("00000000-0000-0000-0000-000000000033");
|
||||||
pub const UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV: Uuid =
|
pub const UUID_IDM_HP_SERVICE_ACCOUNT_INTO_PERSON_MIGRATE_PRIV: Uuid =
|
||||||
uuid!("00000000-0000-0000-0000-000000000034");
|
uuid!("00000000-0000-0000-0000-000000000034");
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ pub const UUID_IDM_UNIX_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-0000000000
|
||||||
pub const UUID_IDM_PEOPLE_ON_BOARDING: Uuid = uuid!("00000000-0000-0000-0000-000000000045");
|
pub const UUID_IDM_PEOPLE_ON_BOARDING: Uuid = uuid!("00000000-0000-0000-0000-000000000045");
|
||||||
pub const UUID_IDM_SERVICE_ACCOUNT_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000046");
|
pub const UUID_IDM_SERVICE_ACCOUNT_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000046");
|
||||||
pub const UUID_IDM_ACCOUNT_POLICY_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000047");
|
pub const UUID_IDM_ACCOUNT_POLICY_ADMINS: Uuid = uuid!("00000000-0000-0000-0000-000000000047");
|
||||||
|
pub const UUID_IDM_PEOPLE_SELF_NAME_WRITE: Uuid = uuid!("00000000-0000-0000-0000-000000000048");
|
||||||
|
|
||||||
//
|
//
|
||||||
pub const UUID_IDM_HIGH_PRIVILEGE: Uuid = uuid!("00000000-0000-0000-0000-000000001000");
|
pub const UUID_IDM_HIGH_PRIVILEGE: Uuid = uuid!("00000000-0000-0000-0000-000000001000");
|
||||||
|
|
|
@ -635,6 +635,10 @@ impl Entry<EntryInit, EntryNew> {
|
||||||
self.add_ava_int(attr, value);
|
self.add_ava_int(attr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_ava(&mut self, attr: Attribute) {
|
||||||
|
self.attrs.remove(attr.as_ref());
|
||||||
|
}
|
||||||
|
|
||||||
/// Replace the existing content of an attribute set of this Entry, with a new set of Values.
|
/// Replace the existing content of an attribute set of this Entry, with a new set of Values.
|
||||||
pub fn set_ava<T>(&mut self, attr: Attribute, iter: T)
|
pub fn set_ava<T>(&mut self, attr: Attribute, iter: T)
|
||||||
where
|
where
|
||||||
|
|
|
@ -231,6 +231,11 @@ mod tests {
|
||||||
Attribute::DirectMemberOf,
|
Attribute::DirectMemberOf,
|
||||||
Value::Refer(UUID_IDM_ALL_ACCOUNTS),
|
Value::Refer(UUID_IDM_ALL_ACCOUNTS),
|
||||||
);
|
);
|
||||||
|
// Indirectly via all persons
|
||||||
|
e.add_ava(
|
||||||
|
Attribute::MemberOf,
|
||||||
|
Value::Refer(UUID_IDM_PEOPLE_SELF_NAME_WRITE),
|
||||||
|
);
|
||||||
// we also add the name_history ava!
|
// we also add the name_history ava!
|
||||||
e.add_ava(
|
e.add_ava(
|
||||||
Attribute::NameHistory,
|
Attribute::NameHistory,
|
||||||
|
|
|
@ -190,13 +190,25 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
e: Entry<EntryInit, EntryNew>,
|
e: Entry<EntryInit, EntryNew>,
|
||||||
) -> Result<(), OperationError> {
|
) -> Result<(), OperationError> {
|
||||||
trace!("internal_migrate_or_create operating on {:?}", e.get_uuid());
|
self.internal_migrate_or_create_ignore_attrs(e, &[])
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is the same as [internal_migrate_or_create] but it will ignore the specified
|
||||||
|
/// list of attributes, so that if an admin has modified those values then we don't
|
||||||
|
/// stomp them.
|
||||||
|
#[instrument(level = "trace", skip_all)]
|
||||||
|
pub fn internal_migrate_or_create_ignore_attrs(
|
||||||
|
&mut self,
|
||||||
|
mut e: Entry<EntryInit, EntryNew>,
|
||||||
|
attrs: &[Attribute],
|
||||||
|
) -> Result<(), OperationError> {
|
||||||
|
trace!("operating on {:?}", e.get_uuid());
|
||||||
|
|
||||||
let Some(filt) = e.filter_from_attrs(&[Attribute::Uuid.into()]) else {
|
let Some(filt) = e.filter_from_attrs(&[Attribute::Uuid.into()]) else {
|
||||||
return Err(OperationError::FilterGeneration);
|
return Err(OperationError::FilterGeneration);
|
||||||
};
|
};
|
||||||
|
|
||||||
trace!("internal_migrate_or_create search {:?}", filt);
|
trace!("search {:?}", filt);
|
||||||
|
|
||||||
let results = self.internal_search(filt.clone())?;
|
let results = self.internal_search(filt.clone())?;
|
||||||
|
|
||||||
|
@ -204,11 +216,16 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
// It does not exist. Create it.
|
// It does not exist. Create it.
|
||||||
self.internal_create(vec![e])
|
self.internal_create(vec![e])
|
||||||
} else if results.len() == 1 {
|
} else if results.len() == 1 {
|
||||||
|
// For each ignored attr, we remove it from entry.
|
||||||
|
for attr in attrs.iter() {
|
||||||
|
e.remove_ava(*attr);
|
||||||
|
}
|
||||||
|
|
||||||
// If the thing is subset, pass
|
// If the thing is subset, pass
|
||||||
match e.gen_modlist_assert(&self.schema) {
|
match e.gen_modlist_assert(&self.schema) {
|
||||||
Ok(modlist) => {
|
Ok(modlist) => {
|
||||||
// Apply to &results[0]
|
// Apply to &results[0]
|
||||||
trace!("Generated modlist -> {:?}", modlist);
|
trace!(?modlist);
|
||||||
self.internal_modify(&filt, &modlist)
|
self.internal_modify(&filt, &modlist)
|
||||||
}
|
}
|
||||||
Err(e) => Err(OperationError::SchemaViolation(e)),
|
Err(e) => Err(OperationError::SchemaViolation(e)),
|
||||||
|
@ -622,7 +639,36 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
|
|
||||||
self.reload()?;
|
self.reload()?;
|
||||||
|
|
||||||
// Post schema changes.
|
// Update access controls
|
||||||
|
let idm_data = [
|
||||||
|
BUILTIN_GROUP_PEOPLE_SELF_NAME_WRITE_DL7
|
||||||
|
.clone()
|
||||||
|
.try_into()?,
|
||||||
|
IDM_PEOPLE_SELF_MAIL_WRITE_DL7.clone().try_into()?,
|
||||||
|
];
|
||||||
|
|
||||||
|
idm_data
|
||||||
|
.into_iter()
|
||||||
|
.try_for_each(|entry| {
|
||||||
|
self.internal_migrate_or_create_ignore_attrs(entry, &[Attribute::Member])
|
||||||
|
})
|
||||||
|
.map_err(|err| {
|
||||||
|
error!(?err, "migrate_domain_6_to_7 -> Error");
|
||||||
|
err
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let idm_data = [
|
||||||
|
IDM_ACP_SELF_WRITE_DL7.clone().into(),
|
||||||
|
IDM_ACP_SELF_NAME_WRITE_DL7.clone().into(),
|
||||||
|
];
|
||||||
|
|
||||||
|
idm_data
|
||||||
|
.into_iter()
|
||||||
|
.try_for_each(|entry| self.internal_migrate_or_create(entry))
|
||||||
|
.map_err(|err| {
|
||||||
|
error!(?err, "migrate_domain_6_to_7 -> Error");
|
||||||
|
err
|
||||||
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue