1use super::ScimEntryGetQuery;
3use super::ScimOauth2ClaimMapJoinChar;
4use crate::attribute::{Attribute, SubAttribute};
5use serde::{Deserialize, Serialize};
6use serde_json::Value as JsonValue;
7use serde_with::formats::PreferMany;
8use serde_with::OneOrMany;
9use serde_with::{base64, formats, serde_as, skip_serializing_none};
10use sshkey_attest::proto::PublicKey as SshPublicKey;
11use std::collections::{BTreeMap, BTreeSet};
12use time::format_description::well_known::Rfc3339;
13use time::OffsetDateTime;
14use uuid::Uuid;
15
16pub type ScimSshPublicKeys = Vec<ScimSshPublicKey>;
17
18#[derive(Deserialize, Serialize, Debug, Clone)]
19#[serde(deny_unknown_fields, rename_all = "camelCase")]
20pub struct ScimSshPublicKey {
21 pub label: String,
22 pub value: SshPublicKey,
23}
24
25#[serde_as]
26#[skip_serializing_none]
27#[derive(Deserialize, Serialize, Debug, Clone)]
28#[serde(deny_unknown_fields, rename_all = "camelCase")]
29pub struct ScimReference {
30 pub uuid: Option<Uuid>,
31 pub value: Option<String>,
32}
33
34pub type ScimReferences = Vec<ScimReference>;
35
36#[serde_as]
37#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
38#[serde(transparent)]
39pub struct ScimDateTime {
40 #[serde_as(as = "Rfc3339")]
41 pub date_time: OffsetDateTime,
42}
43
44#[serde_as]
45#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
46#[serde(rename_all = "camelCase")]
47pub struct ScimCertificate {
48 #[serde_as(as = "base64::Base64<base64::UrlSafe, formats::Unpadded>")]
49 pub der: Vec<u8>,
50}
51
52#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
53#[serde(rename_all = "camelCase")]
54pub struct ScimAddress {
55 pub street_address: String,
56 pub locality: String,
57 pub region: String,
58 pub postal_code: String,
59 pub country: String,
60}
61
62#[serde_as]
63#[derive(Deserialize, Serialize, Debug, Clone)]
64#[serde(rename_all = "camelCase")]
65pub struct ScimOAuth2ClaimMap {
66 pub group: Option<String>,
67 pub group_uuid: Option<Uuid>,
68 pub claim: String,
69 pub join_char: ScimOauth2ClaimMapJoinChar,
70 pub values: BTreeSet<String>,
71}
72
73#[serde_as]
74#[derive(Deserialize, Serialize, Debug, Clone)]
75#[serde(rename_all = "camelCase")]
76pub struct ScimOAuth2ScopeMap {
77 pub group: Option<String>,
78 pub group_uuid: Option<Uuid>,
79 pub scopes: BTreeSet<String>,
80}
81
82#[derive(Serialize, Debug, Clone)]
83pub struct ScimEntryPutKanidm {
84 pub id: Uuid,
85 #[serde(flatten)]
86 pub attrs: BTreeMap<Attribute, Option<super::server::ScimValueKanidm>>,
87}
88
89#[serde_as]
90#[derive(Deserialize, Serialize, Debug, Clone)]
91pub struct ScimStrings(#[serde_as(as = "OneOrMany<_, PreferMany>")] pub Vec<String>);
92
93#[derive(Debug, Clone, Deserialize, Default)]
94pub struct ScimEntryPutGeneric {
95 pub id: Uuid,
97
98 #[serde(flatten)]
99 pub query: ScimEntryGetQuery,
103
104 #[serde(flatten)]
110 pub attrs: BTreeMap<Attribute, Option<JsonValue>>,
111}
112
113impl TryFrom<ScimEntryPutKanidm> for ScimEntryPutGeneric {
114 type Error = serde_json::Error;
115
116 fn try_from(value: ScimEntryPutKanidm) -> Result<Self, Self::Error> {
117 let ScimEntryPutKanidm { id, attrs } = value;
118
119 let attrs = attrs
120 .into_iter()
121 .map(|(attr, value)| {
122 if let Some(v) = value {
123 serde_json::to_value(v).map(|json_value| (attr, Some(json_value)))
124 } else {
125 Ok((attr, None))
126 }
127 })
128 .collect::<Result<_, _>>()?;
129
130 Ok(ScimEntryPutGeneric {
131 id,
132 attrs,
133 query: Default::default(),
134 })
135 }
136}
137
138#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
139pub struct AttrPath {
140 pub a: Attribute,
141 pub s: Option<SubAttribute>,
142}
143
144impl From<Attribute> for AttrPath {
145 fn from(a: Attribute) -> Self {
146 Self { a, s: None }
147 }
148}
149
150impl From<(Attribute, SubAttribute)> for AttrPath {
151 fn from((a, s): (Attribute, SubAttribute)) -> Self {
152 Self { a, s: Some(s) }
153 }
154}
155
156#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
157pub enum ScimFilter {
158 Or(Box<ScimFilter>, Box<ScimFilter>),
159 And(Box<ScimFilter>, Box<ScimFilter>),
160 Not(Box<ScimFilter>),
161
162 Present(AttrPath),
163 Equal(AttrPath, JsonValue),
164 NotEqual(AttrPath, JsonValue),
165 Contains(AttrPath, JsonValue),
166 StartsWith(AttrPath, JsonValue),
167 EndsWith(AttrPath, JsonValue),
168 Greater(AttrPath, JsonValue),
169 Less(AttrPath, JsonValue),
170 GreaterOrEqual(AttrPath, JsonValue),
171 LessOrEqual(AttrPath, JsonValue),
172
173 Complex(Attribute, Box<ScimComplexFilter>),
174}
175
176#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
177pub enum ScimComplexFilter {
178 Or(Box<ScimComplexFilter>, Box<ScimComplexFilter>),
179 And(Box<ScimComplexFilter>, Box<ScimComplexFilter>),
180 Not(Box<ScimComplexFilter>),
181
182 Present(SubAttribute),
183 Equal(SubAttribute, JsonValue),
184 NotEqual(SubAttribute, JsonValue),
185 Contains(SubAttribute, JsonValue),
186 StartsWith(SubAttribute, JsonValue),
187 EndsWith(SubAttribute, JsonValue),
188 Greater(SubAttribute, JsonValue),
189 Less(SubAttribute, JsonValue),
190 GreaterOrEqual(SubAttribute, JsonValue),
191 LessOrEqual(SubAttribute, JsonValue),
192}