mirror of
https://github.com/kanidm/kanidm.git
synced 2025-04-29 13:45:04 +02:00
Progress
This commit is contained in:
parent
298ce0c9ce
commit
0fe42f62bd
|
@ -214,6 +214,7 @@ pub enum OperationError {
|
||||||
SC0025UiHintSyntaxInvalid,
|
SC0025UiHintSyntaxInvalid,
|
||||||
SC0026Utf8SyntaxInvalid,
|
SC0026Utf8SyntaxInvalid,
|
||||||
SC0027ClassSetInvalid,
|
SC0027ClassSetInvalid,
|
||||||
|
SC0028CreatedUuidsInvalid,
|
||||||
// Migration
|
// Migration
|
||||||
MG0001InvalidReMigrationLevel,
|
MG0001InvalidReMigrationLevel,
|
||||||
MG0002RaiseDomainLevelExceedsMaximum,
|
MG0002RaiseDomainLevelExceedsMaximum,
|
||||||
|
@ -494,6 +495,7 @@ impl OperationError {
|
||||||
Self::SC0025UiHintSyntaxInvalid => Some("A SCIM UiHint contained invalid syntax".into()),
|
Self::SC0025UiHintSyntaxInvalid => Some("A SCIM UiHint contained invalid syntax".into()),
|
||||||
Self::SC0026Utf8SyntaxInvalid => Some("A SCIM Utf8 String Scope Map contained invalid syntax".into()),
|
Self::SC0026Utf8SyntaxInvalid => Some("A SCIM Utf8 String Scope Map contained invalid syntax".into()),
|
||||||
Self::SC0027ClassSetInvalid => Some("The internal set of class templates used in this create operation was invalid. THIS IS A BUG.".into()),
|
Self::SC0027ClassSetInvalid => Some("The internal set of class templates used in this create operation was invalid. THIS IS A BUG.".into()),
|
||||||
|
Self::SC0028CreatedUuidsInvalid => Some("The internal create query did not return the set of created UUIDs. THIS IS A BUG".into()),
|
||||||
|
|
||||||
Self::UI0001ChallengeSerialisation => Some("The WebAuthn challenge was unable to be serialised.".into()),
|
Self::UI0001ChallengeSerialisation => Some("The WebAuthn challenge was unable to be serialised.".into()),
|
||||||
Self::UI0002InvalidState => Some("The credential update process returned an invalid state transition.".into()),
|
Self::UI0002InvalidState => Some("The credential update process returned an invalid state transition.".into()),
|
||||||
|
|
|
@ -32,6 +32,18 @@ pub struct ScimReference {
|
||||||
pub value: Option<String>,
|
pub value: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for ScimReference
|
||||||
|
where
|
||||||
|
T: AsRef<str>,
|
||||||
|
{
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
ScimReference {
|
||||||
|
uuid: None,
|
||||||
|
value: Some(value.as_ref().to_string()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub type ScimReferences = Vec<ScimReference>;
|
pub type ScimReferences = Vec<ScimReference>;
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
|
@ -82,21 +94,27 @@ pub struct ScimOAuth2ScopeMap {
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Serialize, Debug, Clone)]
|
#[derive(Serialize, Debug, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct ScimEntryApplicationPost {
|
pub struct ScimEntryApplicationPost {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub display_name: String,
|
pub displayname: String,
|
||||||
|
pub linked_group: ScimReference,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[serde_as]
|
#[serde_as]
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "snake_case")]
|
||||||
pub struct ScimEntryApplication {
|
pub struct ScimEntryApplication {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub header: ScimEntryHeader,
|
pub header: ScimEntryHeader,
|
||||||
|
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub display_name: String,
|
pub displayname: String,
|
||||||
|
|
||||||
|
pub linked_group: Vec<super::ScimReference>,
|
||||||
|
|
||||||
|
#[serde(flatten)]
|
||||||
|
pub attrs: BTreeMap<Attribute, JsonValue>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Debug, Clone)]
|
#[derive(Serialize, Debug, Clone)]
|
||||||
|
|
|
@ -18,13 +18,13 @@
|
||||||
|
|
||||||
use crate::attribute::Attribute;
|
use crate::attribute::Attribute;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde_with::formats::CommaSeparator;
|
||||||
|
use serde_with::{serde_as, skip_serializing_none, StringWithSeparator};
|
||||||
use sshkey_attest::proto::PublicKey as SshPublicKey;
|
use sshkey_attest::proto::PublicKey as SshPublicKey;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::ops::Not;
|
use std::ops::Not;
|
||||||
use utoipa::ToSchema;
|
use utoipa::ToSchema;
|
||||||
|
use uuid::Uuid;
|
||||||
use serde_with::formats::CommaSeparator;
|
|
||||||
use serde_with::{serde_as, skip_serializing_none, StringWithSeparator};
|
|
||||||
|
|
||||||
pub use self::synch::*;
|
pub use self::synch::*;
|
||||||
pub use scim_proto::prelude::*;
|
pub use scim_proto::prelude::*;
|
||||||
|
@ -86,6 +86,13 @@ pub struct ScimSshPublicKey {
|
||||||
pub value: SshPublicKey,
|
pub value: SshPublicKey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq, ToSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct ScimReference {
|
||||||
|
pub uuid: Uuid,
|
||||||
|
pub value: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug, Clone, ToSchema)]
|
#[derive(Deserialize, Serialize, Debug, Clone, ToSchema)]
|
||||||
pub enum ScimOauth2ClaimMapJoinChar {
|
pub enum ScimOauth2ClaimMapJoinChar {
|
||||||
#[serde(rename = ",", alias = "csv")]
|
#[serde(rename = ",", alias = "csv")]
|
||||||
|
|
|
@ -202,7 +202,8 @@ impl QueryServerWriteV1 {
|
||||||
e
|
e
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let scim_create_event = ScimCreateEvent::try_from(ident, classes, entry, &mut idms_prox_write.qs_write)?;
|
let scim_create_event =
|
||||||
|
ScimCreateEvent::try_from(ident, classes, entry, &mut idms_prox_write.qs_write)?;
|
||||||
|
|
||||||
idms_prox_write
|
idms_prox_write
|
||||||
.qs_write
|
.qs_write
|
||||||
|
|
|
@ -78,6 +78,8 @@ impl Modify for SecurityAddon {
|
||||||
super::v1_scim::scim_sync_get,
|
super::v1_scim::scim_sync_get,
|
||||||
super::v1_scim::scim_entry_id_get,
|
super::v1_scim::scim_entry_id_get,
|
||||||
super::v1_scim::scim_person_id_get,
|
super::v1_scim::scim_person_id_get,
|
||||||
|
super::v1_scim::scim_application_post,
|
||||||
|
super::v1_scim::scim_application_id_delete,
|
||||||
|
|
||||||
super::v1::schema_get,
|
super::v1::schema_get,
|
||||||
super::v1::whoami,
|
super::v1::whoami,
|
||||||
|
|
|
@ -43,7 +43,7 @@ fn figure_out_if_we_have_all_the_routes() {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
// work our way through the source files in this package looking for routedefs
|
// work our way through the source files in this package looking for routedefs
|
||||||
let mut found_routes: BTreeMap<String, Vec<(String, String)>> = BTreeMap::new();
|
let mut found_routes: BTreeMap<String, Vec<(String, String)>> = BTreeMap::new();
|
||||||
let walker = walkdir::WalkDir::new(format!("{}/src", env!("CARGO_MANIFEST_DIR")))
|
let walker = walkdir::WalkDir::new(format!("{}/src/https", env!("CARGO_MANIFEST_DIR")))
|
||||||
.follow_links(false)
|
.follow_links(false)
|
||||||
.into_iter();
|
.into_iter();
|
||||||
|
|
||||||
|
|
|
@ -393,7 +393,7 @@ async fn scim_person_id_get(
|
||||||
),
|
),
|
||||||
security(("token_jwt" = [])),
|
security(("token_jwt" = [])),
|
||||||
tag = "scim",
|
tag = "scim",
|
||||||
operation_id = ""
|
operation_id = "scim_application_post"
|
||||||
)]
|
)]
|
||||||
async fn scim_application_post(
|
async fn scim_application_post(
|
||||||
State(state): State<ServerState>,
|
State(state): State<ServerState>,
|
||||||
|
@ -427,18 +427,19 @@ async fn scim_application_post(
|
||||||
),
|
),
|
||||||
security(("token_jwt" = [])),
|
security(("token_jwt" = [])),
|
||||||
tag = "scim",
|
tag = "scim",
|
||||||
operation_id = "scim_person_id_get"
|
operation_id = "scim_application_id_delete"
|
||||||
)]
|
)]
|
||||||
async fn scim_application_id_delete(
|
async fn scim_application_id_delete(
|
||||||
State(state): State<ServerState>,
|
State(state): State<ServerState>,
|
||||||
Path(id): Path<String>,
|
Path(id): Path<String>,
|
||||||
Extension(kopid): Extension<KOpId>,
|
Extension(kopid): Extension<KOpId>,
|
||||||
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
|
||||||
) -> Result<(), WebError> {
|
) -> Result<Json<()>, WebError> {
|
||||||
state
|
state
|
||||||
.qe_w_ref
|
.qe_w_ref
|
||||||
.scim_entry_id_delete(client_auth_info, kopid.eventid, id, EntryClass::Application)
|
.scim_entry_id_delete(client_auth_info, kopid.eventid, id, EntryClass::Application)
|
||||||
.await
|
.await
|
||||||
|
.map(Json::from)
|
||||||
.map_err(WebError::from)
|
.map_err(WebError::from)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -346,6 +346,8 @@ pub struct CreateEvent {
|
||||||
pub entries: Vec<Entry<EntryInit, EntryNew>>,
|
pub entries: Vec<Entry<EntryInit, EntryNew>>,
|
||||||
// Is the CreateEvent from an internal or external source?
|
// Is the CreateEvent from an internal or external source?
|
||||||
// This may affect which plugins are run ...
|
// This may affect which plugins are run ...
|
||||||
|
/// If true, the list of created entry UUID's will be returned.
|
||||||
|
pub return_created_uuids: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CreateEvent {
|
impl CreateEvent {
|
||||||
|
@ -363,7 +365,11 @@ impl CreateEvent {
|
||||||
// What is the correct consuming iterator here? Can we
|
// What is the correct consuming iterator here? Can we
|
||||||
// even do that?
|
// even do that?
|
||||||
match rentries {
|
match rentries {
|
||||||
Ok(entries) => Ok(CreateEvent { ident, entries }),
|
Ok(entries) => Ok(CreateEvent {
|
||||||
|
ident,
|
||||||
|
entries,
|
||||||
|
return_created_uuids: false,
|
||||||
|
}),
|
||||||
Err(e) => Err(e),
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,13 +379,18 @@ impl CreateEvent {
|
||||||
ident: Identity,
|
ident: Identity,
|
||||||
entries: Vec<Entry<EntryInit, EntryNew>>,
|
entries: Vec<Entry<EntryInit, EntryNew>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
CreateEvent { ident, entries }
|
CreateEvent {
|
||||||
|
ident,
|
||||||
|
entries,
|
||||||
|
return_created_uuids: false,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_internal(entries: Vec<Entry<EntryInit, EntryNew>>) -> Self {
|
pub fn new_internal(entries: Vec<Entry<EntryInit, EntryNew>>) -> Self {
|
||||||
CreateEvent {
|
CreateEvent {
|
||||||
ident: Identity::from_internal(),
|
ident: Identity::from_internal(),
|
||||||
entries,
|
entries,
|
||||||
|
return_created_uuids: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -365,7 +365,7 @@ mod tests {
|
||||||
let create = vec![e];
|
let create = vec![e];
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
@ -468,7 +468,7 @@ mod tests {
|
||||||
let create = vec![e];
|
let create = vec![e];
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -205,7 +205,7 @@ mod tests {
|
||||||
|
|
||||||
let create = vec![e];
|
let create = vec![e];
|
||||||
|
|
||||||
run_create_test!(Ok(()), preload, create, None, |_| {});
|
run_create_test!(Ok(None), preload, create, None, |_| {});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -464,7 +464,7 @@ mod tests {
|
||||||
let create = vec![e_dyn];
|
let create = vec![e_dyn];
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
@ -513,7 +513,7 @@ mod tests {
|
||||||
let create = vec![e_group];
|
let create = vec![e_group];
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
@ -562,7 +562,7 @@ mod tests {
|
||||||
let create = vec![e_group];
|
let create = vec![e_group];
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
@ -607,7 +607,7 @@ mod tests {
|
||||||
let create = vec![e_dyn, e_group];
|
let create = vec![e_dyn, e_group];
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -108,7 +108,7 @@ mod tests {
|
||||||
|
|
||||||
let create = vec![ea];
|
let create = vec![ea];
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -136,7 +136,7 @@ mod tests {
|
||||||
let create = vec![e];
|
let create = vec![e];
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -858,7 +858,7 @@ mod tests {
|
||||||
let preload = Vec::with_capacity(0);
|
let preload = Vec::with_capacity(0);
|
||||||
let create = vec![ea, eb];
|
let create = vec![ea, eb];
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
@ -889,7 +889,7 @@ mod tests {
|
||||||
let preload = Vec::with_capacity(0);
|
let preload = Vec::with_capacity(0);
|
||||||
let create = vec![ea, eb, ec];
|
let create = vec![ea, eb, ec];
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
@ -941,7 +941,7 @@ mod tests {
|
||||||
let preload = Vec::with_capacity(0);
|
let preload = Vec::with_capacity(0);
|
||||||
let create = vec![ea, eb, ec];
|
let create = vec![ea, eb, ec];
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
@ -999,7 +999,7 @@ mod tests {
|
||||||
let preload = Vec::with_capacity(0);
|
let preload = Vec::with_capacity(0);
|
||||||
let create = vec![ea, eb, ec, ed];
|
let create = vec![ea, eb, ec, ed];
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -181,7 +181,7 @@ mod tests {
|
||||||
let preload = Vec::with_capacity(0);
|
let preload = Vec::with_capacity(0);
|
||||||
let create = vec![ea];
|
let create = vec![ea];
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -501,7 +501,7 @@ mod tests {
|
||||||
let create = vec![eb];
|
let create = vec![eb];
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
@ -534,7 +534,7 @@ mod tests {
|
||||||
let create = vec![e_group];
|
let create = vec![e_group];
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -233,7 +233,7 @@ mod tests {
|
||||||
let preload = Vec::with_capacity(0);
|
let preload = Vec::with_capacity(0);
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
@ -286,7 +286,7 @@ mod tests {
|
||||||
let preload = Vec::with_capacity(0);
|
let preload = Vec::with_capacity(0);
|
||||||
|
|
||||||
run_create_test!(
|
run_create_test!(
|
||||||
Ok(()),
|
Ok(None),
|
||||||
preload,
|
preload,
|
||||||
create,
|
create,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -7,7 +7,7 @@ impl QueryServerWriteTransaction<'_> {
|
||||||
/// The create event is a raw, read only representation of the request
|
/// The create event is a raw, read only representation of the request
|
||||||
/// that was made to us, including information about the identity
|
/// that was made to us, including information about the identity
|
||||||
/// performing the request.
|
/// performing the request.
|
||||||
pub fn create(&mut self, ce: &CreateEvent) -> Result<(), OperationError> {
|
pub fn create(&mut self, ce: &CreateEvent) -> Result<Option<Vec<Uuid>>, OperationError> {
|
||||||
if !ce.ident.is_internal() {
|
if !ce.ident.is_internal() {
|
||||||
security_info!(name = %ce.ident, "create initiator");
|
security_info!(name = %ce.ident, "create initiator");
|
||||||
}
|
}
|
||||||
|
@ -174,7 +174,12 @@ impl QueryServerWriteTransaction<'_> {
|
||||||
} else {
|
} else {
|
||||||
admin_info!("Create operation success");
|
admin_info!("Create operation success");
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
|
if ce.return_created_uuids {
|
||||||
|
Ok(Some(commit_cand.iter().map(|e| e.get_uuid()).collect()))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn internal_create(
|
pub fn internal_create(
|
||||||
|
@ -182,7 +187,7 @@ impl QueryServerWriteTransaction<'_> {
|
||||||
entries: Vec<Entry<EntryInit, EntryNew>>,
|
entries: Vec<Entry<EntryInit, EntryNew>>,
|
||||||
) -> Result<(), OperationError> {
|
) -> Result<(), OperationError> {
|
||||||
let ce = CreateEvent::new_internal(entries);
|
let ce = CreateEvent::new_internal(entries);
|
||||||
self.create(&ce)
|
self.create(&ce).map(|_| ())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,12 +74,7 @@ impl ScimCreateEvent {
|
||||||
})
|
})
|
||||||
.collect::<Result<EntryInitNew, _>>()?;
|
.collect::<Result<EntryInitNew, _>>()?;
|
||||||
|
|
||||||
|
let classes = ValueSetIutf8::from_iter(classes.iter().map(|cls| cls.as_ref()))
|
||||||
let classes =
|
|
||||||
ValueSetIutf8::from_iter(
|
|
||||||
classes.iter()
|
|
||||||
.map(|cls| cls.as_ref())
|
|
||||||
)
|
|
||||||
.ok_or(OperationError::SC0027ClassSetInvalid)?;
|
.ok_or(OperationError::SC0027ClassSetInvalid)?;
|
||||||
|
|
||||||
entry.set_ava_set(&Attribute::Class, classes);
|
entry.set_ava_set(&Attribute::Class, classes);
|
||||||
|
@ -179,17 +174,21 @@ impl QueryServerWriteTransaction<'_> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scim_create(&mut self, scim_create: ScimCreateEvent) -> Result<(), OperationError> {
|
pub fn scim_create(
|
||||||
let ScimCreateEvent {
|
&mut self,
|
||||||
ident, entry
|
scim_create: ScimCreateEvent,
|
||||||
} = scim_create;
|
) -> Result<ScimEntryKanidm, OperationError> {
|
||||||
|
let ScimCreateEvent { ident, entry } = scim_create;
|
||||||
|
|
||||||
let create_event = CreateEvent {
|
let create_event = CreateEvent {
|
||||||
ident,
|
ident,
|
||||||
entries: vec![entry],
|
entries: vec![entry],
|
||||||
|
return_created_uuids: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut changed_uuids = self.create(&create_event)?;
|
let changed_uuids = self.create(&create_event)?;
|
||||||
|
|
||||||
|
let mut changed_uuids = changed_uuids.ok_or(OperationError::SC0028CreatedUuidsInvalid)?;
|
||||||
|
|
||||||
let target = if let Some(target) = changed_uuids.pop() {
|
let target = if let Some(target) = changed_uuids.pop() {
|
||||||
if !changed_uuids.is_empty() {
|
if !changed_uuids.is_empty() {
|
||||||
|
@ -214,7 +213,7 @@ impl QueryServerWriteTransaction<'_> {
|
||||||
let f_valid = f_intent_valid.clone().into_ignore_hidden();
|
let f_valid = f_intent_valid.clone().into_ignore_hidden();
|
||||||
|
|
||||||
let se = SearchEvent {
|
let se = SearchEvent {
|
||||||
ident,
|
ident: create_event.ident,
|
||||||
filter: f_valid,
|
filter: f_valid,
|
||||||
filter_orig: f_intent_valid,
|
filter_orig: f_intent_valid,
|
||||||
// Return all attributes
|
// Return all attributes
|
||||||
|
|
|
@ -238,6 +238,13 @@ impl ValueSetScimPut for ValueSetRefer {
|
||||||
fn from_scim_json_put(value: JsonValue) -> Result<ValueSetResolveStatus, OperationError> {
|
fn from_scim_json_put(value: JsonValue) -> Result<ValueSetResolveStatus, OperationError> {
|
||||||
use kanidm_proto::scim_v1::client::{ScimReference, ScimReferences};
|
use kanidm_proto::scim_v1::client::{ScimReference, ScimReferences};
|
||||||
|
|
||||||
|
// May be a single reference, lets wrap it in an array to proceed.
|
||||||
|
let value = if !value.is_array() && value.is_object() {
|
||||||
|
JsonValue::Array(vec![value])
|
||||||
|
} else {
|
||||||
|
value
|
||||||
|
};
|
||||||
|
|
||||||
let scim_refs: ScimReferences = serde_json::from_value(value).map_err(|err| {
|
let scim_refs: ScimReferences = serde_json::from_value(value).map_err(|err| {
|
||||||
warn!(?err, "Invalid SCIM reference set syntax");
|
warn!(?err, "Invalid SCIM reference set syntax");
|
||||||
OperationError::SC0002ReferenceSyntaxInvalid
|
OperationError::SC0002ReferenceSyntaxInvalid
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
|
use kanidm_proto::scim_v1::client::{ScimEntryApplicationPost, ScimReference};
|
||||||
use kanidmd_testkit::{AsyncTestEnvironment, IDM_ADMIN_TEST_PASSWORD, IDM_ADMIN_TEST_USER};
|
use kanidmd_testkit::{AsyncTestEnvironment, IDM_ADMIN_TEST_PASSWORD, IDM_ADMIN_TEST_USER};
|
||||||
use ldap3_client::LdapClientBuilder;
|
use ldap3_client::LdapClientBuilder;
|
||||||
|
use tracing::debug;
|
||||||
use kanidm_proto::scim_v1::client::ScimEntryApplicationPost;
|
|
||||||
|
|
||||||
const TEST_PERSON: &str = "user_mcuserton";
|
const TEST_PERSON: &str = "user_mcuserton";
|
||||||
|
const TEST_GROUP: &str = "group_mcgroupington";
|
||||||
|
|
||||||
#[kanidmd_testkit::test(ldap = true)]
|
#[kanidmd_testkit::test(ldap = true)]
|
||||||
async fn test_ldap_basic_unix_bind(test_env: &AsyncTestEnvironment) {
|
async fn test_ldap_basic_unix_bind(test_env: &AsyncTestEnvironment) {
|
||||||
|
@ -41,18 +42,26 @@ async fn test_ldap_application_password_basic(test_env: &AsyncTestEnvironment) {
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create the user");
|
.expect("Failed to create the user");
|
||||||
|
|
||||||
|
idm_admin_rsclient
|
||||||
|
.idm_group_create(TEST_GROUP, None)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create test group");
|
||||||
|
|
||||||
// Create two applications
|
// Create two applications
|
||||||
|
|
||||||
let application_1 = ScimEntryApplicationPost {
|
let application_1 = ScimEntryApplicationPost {
|
||||||
name: APPLICATION_1_NAME.to_string(),
|
name: APPLICATION_1_NAME.to_string(),
|
||||||
display_name: APPLICATION_1_NAME.to_string(),
|
displayname: APPLICATION_1_NAME.to_string(),
|
||||||
|
linked_group: ScimReference::from(TEST_GROUP),
|
||||||
};
|
};
|
||||||
|
|
||||||
let _application_entry = idm_admin_rsclient
|
let application_entry = idm_admin_rsclient
|
||||||
.idm_application_create(&application_1)
|
.idm_application_create(&application_1)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create the user");
|
.expect("Failed to create the user");
|
||||||
|
|
||||||
|
debug!(?application_entry);
|
||||||
|
|
||||||
// List, get them.
|
// List, get them.
|
||||||
|
|
||||||
// Login as the person
|
// Login as the person
|
||||||
|
@ -69,11 +78,13 @@ async fn test_ldap_application_password_basic(test_env: &AsyncTestEnvironment) {
|
||||||
|
|
||||||
// let mut ldap_client = LdapClientBuilder::new(ldap_url).build().await.unwrap();
|
// let mut ldap_client = LdapClientBuilder::new(ldap_url).build().await.unwrap();
|
||||||
|
|
||||||
idm_admin_rsclient
|
let result = idm_admin_rsclient
|
||||||
.idm_application_delete(APPLICATION_1_NAME)
|
.idm_application_delete(APPLICATION_1_NAME)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create the user");
|
.expect("Failed to create the user");
|
||||||
|
|
||||||
|
debug!(?result);
|
||||||
|
|
||||||
// Delete the applications
|
// Delete the applications
|
||||||
|
|
||||||
// Check that you can no longer bind.
|
// Check that you can no longer bind.
|
||||||
|
|
Loading…
Reference in a new issue