mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Resolve incorrect SCIM Sync serialisation (#3047)
This commit is contained in:
parent
004e263f90
commit
fb3e7a01bc
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -5375,6 +5375,7 @@ dependencies = [
|
|||
"peg",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_with",
|
||||
"time",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
|
|
@ -19,6 +19,7 @@ doctest = false
|
|||
base64urlsafedata = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
serde_with = { workspace = true }
|
||||
peg = { workspace = true }
|
||||
time = { workspace = true, features = [
|
||||
"local-offset",
|
||||
|
|
|
@ -5,7 +5,9 @@ use url::Url;
|
|||
use uuid::Uuid;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_with::skip_serializing_none;
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Name {
|
||||
|
@ -73,7 +75,8 @@ impl fmt::Display for Timezone {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MultiValueAttr {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -85,6 +88,7 @@ pub struct MultiValueAttr {
|
|||
pub value: String,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Photo {
|
||||
|
@ -97,6 +101,7 @@ pub struct Photo {
|
|||
value: Url,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct Binary {
|
||||
#[serde(rename = "type")]
|
||||
|
@ -108,6 +113,7 @@ pub struct Binary {
|
|||
value: Base64UrlSafeData,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Address {
|
||||
|
@ -130,6 +136,7 @@ enum Membership {
|
|||
}
|
||||
*/
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Group {
|
||||
|
@ -141,6 +148,7 @@ pub struct Group {
|
|||
display: String,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct User {
|
||||
|
@ -163,17 +171,23 @@ pub struct User {
|
|||
timezone: Option<Timezone>,
|
||||
active: bool,
|
||||
password: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
emails: Vec<MultiValueAttr>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
phone_numbers: Vec<MultiValueAttr>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
ims: Vec<MultiValueAttr>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
photos: Vec<Photo>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
addresses: Vec<Address>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
groups: Vec<Group>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
entitlements: Vec<MultiValueAttr>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
roles: Vec<MultiValueAttr>,
|
||||
#[serde(default)]
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
x509certificates: Vec<Binary>,
|
||||
}
|
||||
|
||||
|
|
|
@ -59,4 +59,59 @@ mod tests {
|
|||
fn test_scim_kani_to_rfc() {
|
||||
// Assert that a kanidm strong entry can convert to rfc.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scim_sync_kani_to_rfc() {
|
||||
use super::*;
|
||||
|
||||
// Group
|
||||
let group_uuid = uuid::uuid!("2d0a9e7c-cc08-4ca2-8d7f-114f9abcfc8a");
|
||||
|
||||
let group = ScimSyncGroup::builder("testgroup".to_string(), group_uuid)
|
||||
.set_description(Some("test desc".to_string()))
|
||||
.set_gidnumber(Some(12345))
|
||||
.set_members(vec!["member_a".to_string(), "member_a".to_string()].into_iter())
|
||||
.set_external_id(Some("cn=testgroup".to_string()))
|
||||
.build();
|
||||
|
||||
let entry: Result<ScimEntry, _> = group.try_into();
|
||||
|
||||
assert!(entry.is_ok());
|
||||
|
||||
// User
|
||||
let user_uuid = uuid::uuid!("cb3de098-33fd-4565-9d80-4f7ed6a664e9");
|
||||
|
||||
let user_sshkey = "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBENubZikrb8hu+HeVRdZ0pp/VAk2qv4JDbuJhvD0yNdWDL2e3cBbERiDeNPkWx58Q4rVnxkbV1fa8E2waRtT91wAAAAEc3NoOg== testuser@fidokey";
|
||||
|
||||
let person =
|
||||
ScimSyncPerson::builder(user_uuid, "testuser".to_string(), "Test User".to_string())
|
||||
.set_password_import(Some("new_password".to_string()))
|
||||
.set_unix_password_import(Some("new_password".to_string()))
|
||||
.set_totp_import(vec![ScimTotp {
|
||||
external_id: "Totp".to_string(),
|
||||
secret: "abcd".to_string(),
|
||||
algo: "SHA3".to_string(),
|
||||
step: 60,
|
||||
digits: 8,
|
||||
}])
|
||||
.set_mail(vec![MultiValueAttr {
|
||||
primary: Some(true),
|
||||
value: "testuser@example.com".to_string(),
|
||||
..Default::default()
|
||||
}])
|
||||
.set_ssh_publickey(vec![ScimSshPubKey {
|
||||
label: "Key McKeyface".to_string(),
|
||||
value: user_sshkey.to_string(),
|
||||
}])
|
||||
.set_login_shell(Some("/bin/false".to_string()))
|
||||
.set_account_valid_from(Some("2023-11-28T04:57:55Z".to_string()))
|
||||
.set_account_expire(Some("2023-11-28T04:57:55Z".to_string()))
|
||||
.set_gidnumber(Some(54321))
|
||||
.set_external_id(Some("cn=testuser".to_string()))
|
||||
.build();
|
||||
|
||||
let entry: Result<ScimEntry, _> = person.try_into();
|
||||
|
||||
assert!(entry.is_ok());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ use uuid::Uuid;
|
|||
|
||||
use scim_proto::user::MultiValueAttr;
|
||||
use scim_proto::{ScimEntry, ScimEntryHeader};
|
||||
use serde_with::skip_serializing_none;
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, ToSchema)]
|
||||
|
@ -82,6 +83,7 @@ pub struct ScimSshPubKey {
|
|||
pub value: String,
|
||||
}
|
||||
|
||||
#[skip_serializing_none]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ScimSyncPerson {
|
||||
|
@ -93,9 +95,12 @@ pub struct ScimSyncPerson {
|
|||
pub gidnumber: Option<u32>,
|
||||
pub password_import: Option<String>,
|
||||
pub unix_password_import: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub totp_import: Vec<ScimTotp>,
|
||||
pub login_shell: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub mail: Vec<MultiValueAttr>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub ssh_publickey: Vec<ScimSshPubKey>,
|
||||
pub account_valid_from: Option<String>,
|
||||
pub account_expire: Option<String>,
|
||||
|
|
Loading…
Reference in a new issue