mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
20241012 attr name SCIM fix (#3102)
* Fix handling of attribute to ensure that it is consistently Attribute in scim sync
This commit is contained in:
parent
4e125b5043
commit
1cccebd382
|
@ -540,7 +540,15 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
sse: &'b ScimSyncUpdateEvent,
|
sse: &'b ScimSyncUpdateEvent,
|
||||||
changes: &'b ScimSyncRequest,
|
changes: &'b ScimSyncRequest,
|
||||||
) -> Result<(Uuid, BTreeSet<String>, BTreeMap<Uuid, &'b ScimEntry>, bool), OperationError> {
|
) -> Result<
|
||||||
|
(
|
||||||
|
Uuid,
|
||||||
|
BTreeSet<Attribute>,
|
||||||
|
BTreeMap<Uuid, &'b ScimEntry>,
|
||||||
|
bool,
|
||||||
|
),
|
||||||
|
OperationError,
|
||||||
|
> {
|
||||||
// Assert the token is valid.
|
// Assert the token is valid.
|
||||||
let sync_uuid = match &sse.ident.origin {
|
let sync_uuid = match &sse.ident.origin {
|
||||||
IdentType::User(_) | IdentType::Internal => {
|
IdentType::User(_) | IdentType::Internal => {
|
||||||
|
@ -607,9 +615,9 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
let sync_refresh = matches!(&changes.from_state, ScimSyncState::Refresh);
|
let sync_refresh = matches!(&changes.from_state, ScimSyncState::Refresh);
|
||||||
|
|
||||||
// Get the sync authority set from the entry.
|
// Get the sync authority set from the entry.
|
||||||
let sync_authority_set = sync_entry
|
let sync_authority_set: BTreeSet<Attribute> = sync_entry
|
||||||
.get_ava_as_iutf8(Attribute::SyncYieldAuthority)
|
.get_ava_as_iutf8(Attribute::SyncYieldAuthority)
|
||||||
.cloned()
|
.map(|set| set.iter().map(|s| Attribute::from(s.as_str())).collect())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
// Transform the changes into something that supports lookups.
|
// Transform the changes into something that supports lookups.
|
||||||
|
@ -1114,8 +1122,8 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
scim_ent: &ScimEntry,
|
scim_ent: &ScimEntry,
|
||||||
sync_uuid: Uuid,
|
sync_uuid: Uuid,
|
||||||
sync_allow_class_set: &BTreeMap<String, SchemaClass>,
|
sync_allow_class_set: &BTreeMap<String, SchemaClass>,
|
||||||
sync_allow_attr_set: &BTreeSet<String>,
|
sync_allow_attr_set: &BTreeSet<Attribute>,
|
||||||
phantom_attr_set: &BTreeSet<String>,
|
phantom_attr_set: &BTreeSet<Attribute>,
|
||||||
) -> Result<ModifyList<ModifyInvalid>, OperationError> {
|
) -> Result<ModifyList<ModifyInvalid>, OperationError> {
|
||||||
// What classes did they request for this entry to sync?
|
// What classes did they request for this entry to sync?
|
||||||
let requested_classes = scim_ent.schemas.iter()
|
let requested_classes = scim_ent.schemas.iter()
|
||||||
|
@ -1179,7 +1187,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
//
|
//
|
||||||
// - either we nominate phantom attrs on the classes they can import with
|
// - either we nominate phantom attrs on the classes they can import with
|
||||||
// or we need to always allow them?
|
// or we need to always allow them?
|
||||||
let sync_owned_attrs: BTreeSet<_> = requested_classes
|
let sync_owned_attrs: BTreeSet<Attribute> = requested_classes
|
||||||
.values()
|
.values()
|
||||||
.flat_map(|cls| {
|
.flat_map(|cls| {
|
||||||
cls.systemmay
|
cls.systemmay
|
||||||
|
@ -1188,26 +1196,28 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
.chain(cls.systemmust.iter())
|
.chain(cls.systemmust.iter())
|
||||||
.chain(cls.must.iter())
|
.chain(cls.must.iter())
|
||||||
})
|
})
|
||||||
.map(|s| s.as_str())
|
|
||||||
// Finally, establish if the attribute is syncable. Technically this could probe some attrs
|
// Finally, establish if the attribute is syncable. Technically this could probe some attrs
|
||||||
// multiple times due to how the loop is established, but in reality there are few attr overlaps.
|
// multiple times due to how the loop is established, but in reality there are few attr overlaps.
|
||||||
.filter(|a| sync_allow_attr_set.contains(*a))
|
.filter(|a| sync_allow_attr_set.contains(*a))
|
||||||
// Add in the set of phantom syncable attrs.
|
// Add in the set of phantom syncable attrs.
|
||||||
.chain(phantom_attr_set.iter().map(|s| s.as_str()))
|
.chain(phantom_attr_set.iter())
|
||||||
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
debug!(?sync_owned_attrs);
|
debug!(?sync_owned_attrs);
|
||||||
|
|
||||||
for attr in sync_owned_attrs.iter().copied() {
|
for attr in sync_owned_attrs.iter() {
|
||||||
if !phantom_attr_set.contains(attr) {
|
if !phantom_attr_set.contains(attr) {
|
||||||
// These are the attrs that are "real" and need to be cleaned out first.
|
// These are the attrs that are "real" and need to be cleaned out first.
|
||||||
mods.push(Modify::Purged(attr.into()));
|
mods.push(Modify::Purged(attr.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For each attr in the scim entry, see if it's in the sync_owned set. If so, proceed.
|
// For each attr in the scim entry, see if it's in the sync_owned set. If so, proceed.
|
||||||
for (scim_attr_name, scim_attr) in scim_ent.attrs.iter() {
|
for (scim_attr_name, scim_attr) in scim_ent.attrs.iter() {
|
||||||
if !sync_owned_attrs.contains(scim_attr_name.as_str()) {
|
let scim_attr_name = Attribute::from(scim_attr_name.as_str());
|
||||||
|
|
||||||
|
if !sync_owned_attrs.contains(&scim_attr_name) {
|
||||||
error!(
|
error!(
|
||||||
"Rejecting attribute {} for entry {} which is not sync owned",
|
"Rejecting attribute {} for entry {} which is not sync owned",
|
||||||
scim_attr_name, scim_ent.id
|
scim_attr_name, scim_ent.id
|
||||||
|
@ -1215,9 +1225,6 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
return Err(OperationError::InvalidEntryState);
|
return Err(OperationError::InvalidEntryState);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make it a native attribute name.
|
|
||||||
let scim_attr_name = Attribute::from(scim_attr_name.as_str());
|
|
||||||
|
|
||||||
// Convert each scim_attr to a set of values.
|
// Convert each scim_attr to a set of values.
|
||||||
let values = self
|
let values = self
|
||||||
.scim_attr_to_values(&scim_attr_name, scim_attr)
|
.scim_attr_to_values(&scim_attr_name, scim_attr)
|
||||||
|
@ -1245,7 +1252,7 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
&mut self,
|
&mut self,
|
||||||
change_entries: &BTreeMap<Uuid, &ScimEntry>,
|
change_entries: &BTreeMap<Uuid, &ScimEntry>,
|
||||||
sync_uuid: Uuid,
|
sync_uuid: Uuid,
|
||||||
sync_authority_set: &BTreeSet<String>,
|
sync_authority_set: &BTreeSet<Attribute>,
|
||||||
) -> Result<(), OperationError> {
|
) -> Result<(), OperationError> {
|
||||||
if change_entries.is_empty() {
|
if change_entries.is_empty() {
|
||||||
info!("No change_entries requested");
|
info!("No change_entries requested");
|
||||||
|
@ -1279,23 +1286,23 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let sync_allow_attr_set: BTreeSet<String> = attr_snapshot
|
let sync_allow_attr_set: BTreeSet<Attribute> = attr_snapshot
|
||||||
.values()
|
.values()
|
||||||
// Only add attrs to this if they are both sync allowed AND authority granted.
|
// Only add attrs to this if they are both sync allowed AND authority granted.
|
||||||
.filter_map(|attr| {
|
.filter_map(|attr| {
|
||||||
if attr.sync_allowed && !sync_authority_set.contains(attr.name.as_str()) {
|
if attr.sync_allowed && !sync_authority_set.contains(&attr.name) {
|
||||||
Some(attr.name.to_string())
|
Some(attr.name.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let phantom_attr_set: BTreeSet<String> = attr_snapshot
|
let phantom_attr_set: BTreeSet<Attribute> = attr_snapshot
|
||||||
.values()
|
.values()
|
||||||
.filter_map(|attr| {
|
.filter_map(|attr| {
|
||||||
if attr.phantom && attr.sync_allowed {
|
if attr.phantom && attr.sync_allowed {
|
||||||
Some(attr.name.to_string())
|
Some(attr.name.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue