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