diff --git a/libs/client/src/application.rs b/libs/client/src/application.rs new file mode 100644 index 000000000..6fb611c27 --- /dev/null +++ b/libs/client/src/application.rs @@ -0,0 +1,19 @@ +use crate::{ClientError, KanidmClient}; +use kanidm_proto::scim_v1::client::{ScimEntryApplication, ScimEntryApplicationPost}; + +impl KanidmClient { + /// Delete an application + pub async fn idm_application_delete(&self, id: &str) -> Result<(), ClientError> { + self.perform_delete_request(format!("/scim/v1/Application/{}", id).as_str()) + .await + } + + /// Create an application + pub async fn idm_application_create( + &self, + application: &ScimEntryApplicationPost, + ) -> Result<ScimEntryApplication, ClientError> { + self.perform_post_request("/scim/v1/Application", application) + .await + } +} diff --git a/server/lib/src/server/scim.rs b/server/lib/src/server/scim.rs index 5f785777b..b48c84e3b 100644 --- a/server/lib/src/server/scim.rs +++ b/server/lib/src/server/scim.rs @@ -189,7 +189,51 @@ impl QueryServerWriteTransaction<'_> { entries: vec![entry], }; - self.create(&create_event) + let mut changed_uuids = self.create(&create_event)?; + + let target = if let Some(target) = changed_uuids.pop() { + if !changed_uuids.is_empty() { + // Too many results! + return Err(OperationError::UniqueConstraintViolation); + } + + target + } else { + // No results! + return Err(OperationError::NoMatchingEntries); + }; + + // Now get the entry. We handle a lot of the errors here nicely, + // but if we got to this point, they really can't happen. + let filter_intent = filter!(f_and!([f_eq(Attribute::Uuid, PartialValue::Uuid(target))])); + + let f_intent_valid = filter_intent + .validate(self.get_schema()) + .map_err(OperationError::SchemaViolation)?; + + let f_valid = f_intent_valid.clone().into_ignore_hidden(); + + let se = SearchEvent { + ident, + filter: f_valid, + filter_orig: f_intent_valid, + // Return all attributes + attrs: None, + effective_access_check: false, + }; + + let mut vs = self.search_ext(&se)?; + match vs.pop() { + Some(entry) if vs.is_empty() => entry.to_scim_kanidm(self), + _ => { + if vs.is_empty() { + Err(OperationError::NoMatchingEntries) + } else { + // Multiple entries matched, should not be possible! + Err(OperationError::UniqueConstraintViolation) + } + } + } } pub fn scim_delete(&mut self, scim_delete: ScimDeleteEvent) -> Result<(), OperationError> {