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