1use super::{QueryServerReadV1, QueryServerWriteV1};
2use kanidm_proto::scim_v1::client::ScimEntryPutGeneric;
3use kanidm_proto::scim_v1::{
4 client::ScimEntryPostGeneric, client::ScimFilter, server::ScimEntryKanidm,
5 server::ScimListResponse, ScimEntryGetQuery, ScimSyncRequest, ScimSyncState,
6};
7use kanidmd_lib::idm::scim::{
8 GenerateScimSyncTokenEvent, ScimSyncFinaliseEvent, ScimSyncTerminateEvent, ScimSyncUpdateEvent,
9};
10use kanidmd_lib::idm::server::IdmServerTransaction;
11use kanidmd_lib::prelude::*;
12use kanidmd_lib::server::scim::{ScimCreateEvent, ScimDeleteEvent, ScimEntryPutEvent};
13
14impl QueryServerWriteV1 {
15 #[instrument(
16 level = "info",
17 skip_all,
18 fields(uuid = ?eventid)
19 )]
20 pub async fn handle_sync_account_token_generate(
21 &self,
22 client_auth_info: ClientAuthInfo,
23 uuid_or_name: String,
24 label: String,
25 eventid: Uuid,
26 ) -> Result<String, OperationError> {
27 let ct = duration_from_epoch_now();
28 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
29 let ident = idms_prox_write
30 .validate_client_auth_info_to_ident(client_auth_info, ct)
31 .map_err(|e| {
32 admin_error!(err = ?e, "Invalid identity");
33 e
34 })?;
35
36 let target = idms_prox_write
37 .qs_write
38 .name_to_uuid(uuid_or_name.as_str())
39 .map_err(|e| {
40 admin_error!(err = ?e, "Error resolving id to target");
41 e
42 })?;
43
44 let gte = GenerateScimSyncTokenEvent {
45 ident,
46 target,
47 label,
48 };
49
50 idms_prox_write
51 .scim_sync_generate_token(>e, ct)
52 .map(|token| token.to_string())
53 .and_then(|r| idms_prox_write.commit().map(|_| r))
54 }
55
56 #[instrument(
57 level = "info",
58 skip_all,
59 fields(uuid = ?eventid)
60 )]
61 pub async fn handle_sync_account_token_destroy(
62 &self,
63 client_auth_info: ClientAuthInfo,
64 uuid_or_name: String,
65 eventid: Uuid,
66 ) -> Result<(), OperationError> {
67 let ct = duration_from_epoch_now();
68 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
69 let ident = idms_prox_write
70 .validate_client_auth_info_to_ident(client_auth_info, ct)
71 .map_err(|e| {
72 admin_error!(err = ?e, "Invalid identity");
73 e
74 })?;
75
76 let target = idms_prox_write
77 .qs_write
78 .name_to_uuid(uuid_or_name.as_str())
79 .map_err(|e| {
80 admin_error!(err = ?e, "Error resolving id to target");
81 e
82 })?;
83
84 idms_prox_write
85 .sync_account_destroy_token(&ident, target, ct)
86 .and_then(|r| idms_prox_write.commit().map(|_| r))
87 }
88
89 #[instrument(
90 level = "info",
91 skip_all,
92 fields(uuid = ?eventid)
93 )]
94 pub async fn handle_sync_account_finalise(
95 &self,
96 client_auth_info: ClientAuthInfo,
97 uuid_or_name: String,
98 eventid: Uuid,
99 ) -> Result<(), OperationError> {
100 let ct = duration_from_epoch_now();
101 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
102 let ident = idms_prox_write
103 .validate_client_auth_info_to_ident(client_auth_info, ct)
104 .map_err(|e| {
105 admin_error!(err = ?e, "Invalid identity");
106 e
107 })?;
108
109 let target = idms_prox_write
110 .qs_write
111 .name_to_uuid(uuid_or_name.as_str())
112 .map_err(|e| {
113 admin_error!(err = ?e, "Error resolving id to target");
114 e
115 })?;
116
117 let sfe = ScimSyncFinaliseEvent { ident, target };
118
119 idms_prox_write
120 .scim_sync_finalise(&sfe)
121 .and_then(|r| idms_prox_write.commit().map(|_| r))
122 }
123
124 #[instrument(
125 level = "info",
126 skip_all,
127 fields(uuid = ?eventid)
128 )]
129 pub async fn handle_sync_account_terminate(
130 &self,
131 client_auth_info: ClientAuthInfo,
132 uuid_or_name: String,
133 eventid: Uuid,
134 ) -> Result<(), OperationError> {
135 let ct = duration_from_epoch_now();
136 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
137 let ident = idms_prox_write
138 .validate_client_auth_info_to_ident(client_auth_info, ct)
139 .map_err(|e| {
140 admin_error!(err = ?e, "Invalid identity");
141 e
142 })?;
143
144 let target = idms_prox_write
145 .qs_write
146 .name_to_uuid(uuid_or_name.as_str())
147 .map_err(|e| {
148 admin_error!(err = ?e, "Error resolving id to target");
149 e
150 })?;
151
152 let ste = ScimSyncTerminateEvent { ident, target };
153
154 idms_prox_write
155 .scim_sync_terminate(&ste)
156 .and_then(|r| idms_prox_write.commit().map(|_| r))
157 }
158
159 #[instrument(
160 level = "info",
161 skip_all,
162 fields(uuid = ?eventid)
163 )]
164 pub async fn handle_scim_sync_apply(
165 &self,
166 client_auth_info: ClientAuthInfo,
167 changes: ScimSyncRequest,
168 eventid: Uuid,
169 ) -> Result<(), OperationError> {
170 let ct = duration_from_epoch_now();
171 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
172
173 let ident =
174 idms_prox_write.validate_sync_client_auth_info_to_ident(client_auth_info, ct)?;
175
176 let sse = ScimSyncUpdateEvent { ident };
177
178 idms_prox_write
179 .scim_sync_apply(&sse, &changes, ct)
180 .and_then(|r| idms_prox_write.commit().map(|_| r))
181 }
182
183 #[instrument(
184 level = "info",
185 skip_all,
186 fields(uuid = ?eventid)
187 )]
188 pub async fn scim_entry_create(
189 &self,
190 client_auth_info: ClientAuthInfo,
191 eventid: Uuid,
192 classes: &[EntryClass],
193 entry: ScimEntryPostGeneric,
194 ) -> Result<ScimEntryKanidm, OperationError> {
195 let ct = duration_from_epoch_now();
196 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
197 let ident = idms_prox_write
198 .validate_client_auth_info_to_ident(client_auth_info, ct)
199 .map_err(|e| {
200 admin_error!(err = ?e, "Invalid identity");
201 e
202 })?;
203
204 let scim_create_event =
205 ScimCreateEvent::try_from(ident, classes, entry, &mut idms_prox_write.qs_write)?;
206
207 idms_prox_write
208 .qs_write
209 .scim_create(scim_create_event)
210 .and_then(|r| idms_prox_write.commit().map(|_| r))
211 }
212
213 #[instrument(
214 level = "info",
215 skip_all,
216 fields(uuid = ?eventid)
217 )]
218 pub async fn scim_entry_id_delete(
219 &self,
220 client_auth_info: ClientAuthInfo,
221 eventid: Uuid,
222 uuid_or_name: String,
223 class: EntryClass,
224 ) -> Result<(), OperationError> {
225 let ct = duration_from_epoch_now();
226 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
227 let ident = idms_prox_write
228 .validate_client_auth_info_to_ident(client_auth_info, ct)
229 .map_err(|e| {
230 admin_error!(err = ?e, "Invalid identity");
231 e
232 })?;
233
234 let target = idms_prox_write
235 .qs_write
236 .name_to_uuid(uuid_or_name.as_str())
237 .map_err(|e| {
238 admin_error!(err = ?e, "Error resolving id to target");
239 e
240 })?;
241
242 let scim_delete_event = ScimDeleteEvent::new(ident, target, class);
243
244 idms_prox_write
245 .qs_write
246 .scim_delete(scim_delete_event)
247 .and_then(|r| idms_prox_write.commit().map(|_| r))
248 }
249
250 #[instrument(
251 level = "info",
252 skip_all,
253 fields(uuid = ?eventid)
254 )]
255 pub async fn handle_scim_entry_put(
256 &self,
257 client_auth_info: ClientAuthInfo,
258 eventid: Uuid,
259 generic: ScimEntryPutGeneric,
260 ) -> Result<ScimEntryKanidm, OperationError> {
261 let ct = duration_from_epoch_now();
262 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
263 let ident = idms_prox_write
264 .validate_client_auth_info_to_ident(client_auth_info, ct)
265 .map_err(|op_err| {
266 admin_error!(err = ?op_err, "Invalid identity");
267 op_err
268 })?;
269
270 let scim_entry_put_event =
271 ScimEntryPutEvent::try_from(ident, generic, &mut idms_prox_write.qs_write)?;
272
273 idms_prox_write
274 .qs_write
275 .scim_put(scim_entry_put_event)
276 .and_then(|r| idms_prox_write.commit().map(|_| r))
277 }
278}
279
280impl QueryServerReadV1 {
281 #[instrument(
282 level = "info",
283 skip_all,
284 fields(uuid = ?eventid)
285 )]
286 pub async fn handle_scim_sync_status(
287 &self,
288 client_auth_info: ClientAuthInfo,
289 eventid: Uuid,
290 ) -> Result<ScimSyncState, OperationError> {
291 let ct = duration_from_epoch_now();
292 let mut idms_prox_read = self.idms.proxy_read().await?;
293
294 let ident = idms_prox_read.validate_sync_client_auth_info_to_ident(client_auth_info, ct)?;
295
296 idms_prox_read.scim_sync_get_state(&ident)
297 }
298
299 #[instrument(
300 level = "info",
301 skip_all,
302 fields(uuid = ?eventid)
303 )]
304 pub async fn scim_entry_id_get(
305 &self,
306 client_auth_info: ClientAuthInfo,
307 eventid: Uuid,
308 uuid_or_name: String,
309 class: EntryClass,
310 query: ScimEntryGetQuery,
311 ) -> Result<ScimEntryKanidm, OperationError> {
312 let ct = duration_from_epoch_now();
313 let mut idms_prox_read = self.idms.proxy_read().await?;
314 let ident = idms_prox_read
315 .validate_client_auth_info_to_ident(client_auth_info, ct)
316 .inspect_err(|err| {
317 error!(?err, "Invalid identity");
318 })?;
319
320 let target_uuid = idms_prox_read
321 .qs_read
322 .name_to_uuid(uuid_or_name.as_str())
323 .inspect_err(|err| {
324 error!(?err, "Error resolving id to target");
325 })?;
326
327 idms_prox_read
328 .qs_read
329 .scim_entry_id_get_ext(target_uuid, class, query, ident)
330 }
331
332 #[instrument(
333 level = "info",
334 skip_all,
335 fields(uuid = ?eventid)
336 )]
337 pub async fn scim_entry_search(
338 &self,
339 client_auth_info: ClientAuthInfo,
340 eventid: Uuid,
341 filter: ScimFilter,
342 query: ScimEntryGetQuery,
343 ) -> Result<ScimListResponse, OperationError> {
344 let ct = duration_from_epoch_now();
345 let mut idms_prox_read = self.idms.proxy_read().await?;
346 let ident = idms_prox_read
347 .validate_client_auth_info_to_ident(client_auth_info, ct)
348 .inspect_err(|err| {
349 error!(?err, "Invalid identity");
350 })?;
351
352 idms_prox_read
353 .qs_read
354 .scim_search_ext(ident, &filter, query)
355 }
356}