1use super::ScimEntryGetQuery;
3use super::ScimOauth2ClaimMapJoinChar;
4use crate::attribute::Attribute;
5use scim_proto::ScimEntryHeader;
6use serde::{Deserialize, Serialize};
7use serde_json::Value as JsonValue;
8use serde_with::formats::PreferMany;
9use serde_with::OneOrMany;
10use serde_with::{base64, formats, serde_as, skip_serializing_none};
11use sshkey_attest::proto::PublicKey as SshPublicKey;
12use std::collections::{BTreeMap, BTreeSet};
13use std::num::NonZeroU64;
14use time::format_description::well_known::Rfc3339;
15use time::OffsetDateTime;
16use utoipa::ToSchema;
17use uuid::Uuid;
18
19pub type ScimSshPublicKeys = Vec<ScimSshPublicKey>;
20
21#[derive(Deserialize, Serialize, Debug, Clone)]
22#[serde(deny_unknown_fields, rename_all = "camelCase")]
23pub struct ScimSshPublicKey {
24 pub label: String,
25 pub value: SshPublicKey,
26}
27
28#[serde_as]
29#[skip_serializing_none]
30#[derive(Deserialize, Serialize, Debug, Clone)]
31#[serde(deny_unknown_fields, rename_all = "camelCase")]
32pub struct ScimReference {
33 pub uuid: Option<Uuid>,
34 pub value: Option<String>,
35}
36
37impl<T> From<T> for ScimReference
38where
39 T: AsRef<str>,
40{
41 fn from(value: T) -> Self {
42 ScimReference {
43 uuid: None,
44 value: Some(value.as_ref().to_string()),
45 }
46 }
47}
48
49pub type ScimReferences = Vec<ScimReference>;
50
51#[serde_as]
52#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
53#[serde(transparent)]
54pub struct ScimDateTime {
55 #[serde_as(as = "Rfc3339")]
56 pub date_time: OffsetDateTime,
57}
58
59#[serde_as]
60#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
61#[serde(rename_all = "camelCase")]
62pub struct ScimCertificate {
63 #[serde_as(as = "base64::Base64<base64::UrlSafe, formats::Unpadded>")]
64 pub der: Vec<u8>,
65}
66
67#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
68#[serde(rename_all = "camelCase")]
69pub struct ScimAddress {
70 pub street_address: String,
71 pub locality: String,
72 pub region: String,
73 pub postal_code: String,
74 pub country: String,
75}
76
77#[serde_as]
78#[derive(Deserialize, Serialize, Debug, Clone)]
79#[serde(rename_all = "camelCase")]
80pub struct ScimOAuth2ClaimMap {
81 pub group: Option<String>,
82 pub group_uuid: Option<Uuid>,
83 pub claim: String,
84 pub join_char: ScimOauth2ClaimMapJoinChar,
85 pub values: BTreeSet<String>,
86}
87
88#[serde_as]
89#[derive(Deserialize, Serialize, Debug, Clone)]
90#[serde(rename_all = "camelCase")]
91pub struct ScimOAuth2ScopeMap {
92 pub group: Option<String>,
93 pub group_uuid: Option<Uuid>,
94 pub scopes: BTreeSet<String>,
95}
96
97#[serde_as]
98#[derive(Serialize, Debug, Clone)]
99#[serde(rename_all = "snake_case")]
100pub struct ScimEntryApplicationPost {
101 pub name: String,
102 pub displayname: String,
103 pub linked_group: ScimReference,
104}
105
106#[serde_as]
107#[derive(Deserialize, Debug, Clone)]
108#[serde(rename_all = "snake_case")]
109pub struct ScimEntryApplication {
110 #[serde(flatten)]
111 pub header: ScimEntryHeader,
112
113 pub name: String,
114 pub displayname: String,
115
116 pub linked_group: Vec<super::ScimReference>,
117
118 #[serde(flatten)]
119 pub attrs: BTreeMap<Attribute, JsonValue>,
120}
121
122#[serde_as]
123#[derive(Deserialize, Clone, Debug)]
124#[serde(rename_all = "camelCase")]
125pub struct ScimListApplication {
126 pub schemas: Vec<String>,
127 pub total_results: u64,
128 pub items_per_page: Option<NonZeroU64>,
129 pub start_index: Option<NonZeroU64>,
130 pub resources: Vec<ScimEntryApplication>,
131}
132
133#[serde_as]
134#[derive(Deserialize, Debug, Clone)]
135#[serde(rename_all = "snake_case")]
136pub struct ScimEntrySchemaClass {
137 #[serde(flatten)]
138 pub header: ScimEntryHeader,
139
140 #[serde(flatten)]
144 pub attrs: BTreeMap<Attribute, JsonValue>,
145}
146
147#[serde_as]
148#[derive(Deserialize, Clone, Debug)]
149#[serde(rename_all = "camelCase")]
150pub struct ScimListSchemaClass {
151 pub schemas: Vec<String>,
152 pub total_results: u64,
153 pub items_per_page: Option<NonZeroU64>,
154 pub start_index: Option<NonZeroU64>,
155 pub resources: Vec<ScimEntrySchemaClass>,
156}
157
158#[serde_as]
159#[derive(Deserialize, Debug, Clone, Serialize)]
160#[serde(rename_all = "snake_case")]
161pub struct ScimEntrySchemaAttribute {
162 #[serde(flatten)]
163 pub header: ScimEntryHeader,
164
165 pub attributename: String,
166 pub description: String,
167 pub multivalue: bool,
169 pub unique: bool,
170 pub syntax: String,
171 #[serde(flatten)]
173 pub attrs: BTreeMap<Attribute, JsonValue>,
174}
175
176#[serde_as]
177#[derive(Deserialize, Clone, Debug)]
178#[serde(rename_all = "camelCase")]
179pub struct ScimListSchemaAttribute {
180 pub schemas: Vec<String>,
181 pub total_results: u64,
182 pub items_per_page: Option<NonZeroU64>,
183 pub start_index: Option<NonZeroU64>,
184 pub resources: Vec<ScimEntrySchemaAttribute>,
185}
186
187#[derive(Serialize, Debug, Clone)]
188pub struct ScimEntryPutKanidm {
189 pub id: Uuid,
190 #[serde(flatten)]
191 pub attrs: BTreeMap<Attribute, Option<super::server::ScimValueKanidm>>,
192}
193
194#[serde_as]
195#[derive(Deserialize, Serialize, Debug, Clone)]
196pub struct ScimStrings(#[serde_as(as = "OneOrMany<_, PreferMany>")] pub Vec<String>);
197
198#[derive(Debug, Clone, Deserialize, Default, ToSchema)]
199pub struct ScimEntryPostGeneric {
200 #[serde(flatten)]
202 #[schema(value_type = Object, additional_properties = true)]
203 pub attrs: BTreeMap<Attribute, JsonValue>,
204}
205
206#[derive(Debug, Clone, Deserialize, Default)]
207pub struct ScimEntryPutGeneric {
208 pub id: Uuid,
210
211 #[serde(flatten)]
212 pub query: ScimEntryGetQuery,
216
217 #[serde(flatten)]
223 pub attrs: BTreeMap<Attribute, Option<JsonValue>>,
224}
225
226impl TryFrom<ScimEntryPutKanidm> for ScimEntryPutGeneric {
227 type Error = serde_json::Error;
228
229 fn try_from(value: ScimEntryPutKanidm) -> Result<Self, Self::Error> {
230 let ScimEntryPutKanidm { id, attrs } = value;
231
232 let attrs = attrs
233 .into_iter()
234 .map(|(attr, value)| {
235 if let Some(v) = value {
236 serde_json::to_value(v).map(|json_value| (attr, Some(json_value)))
237 } else {
238 Ok((attr, None))
239 }
240 })
241 .collect::<Result<_, _>>()?;
242
243 Ok(ScimEntryPutGeneric {
244 id,
245 attrs,
246 query: Default::default(),
247 })
248 }
249}