1use std::iter;
2
3use compact_jwt::JweCompact;
4use kanidm_proto::internal::{
5 CUIntentToken, CUSessionToken, CUStatus, CreateRequest, DeleteRequest, ImageValue,
6 Modify as ProtoModify, ModifyList as ProtoModifyList, ModifyRequest,
7 Oauth2ClaimMapJoin as ProtoOauth2ClaimMapJoin, OperationError,
8};
9use kanidm_proto::v1::{AccountUnixExtend, Entry as ProtoEntry, GroupUnixExtend};
10use std::str::FromStr;
11use time::OffsetDateTime;
12use tracing::{info, instrument, trace};
13use uuid::Uuid;
14
15use kanidmd_lib::{
16 event::{CreateEvent, DeleteEvent, ModifyEvent, ReviveRecycledEvent},
17 filter::{Filter, FilterInvalid},
18 idm::account::DestroySessionTokenEvent,
19 idm::credupdatesession::{
20 CredentialUpdateIntentTokenExchange, CredentialUpdateSessionToken,
21 InitCredentialUpdateEvent, InitCredentialUpdateIntentEvent,
22 },
23 idm::event::{GeneratePasswordEvent, RegenerateRadiusSecretEvent, UnixPasswordChangeEvent},
24 idm::oauth2::{
25 AccessTokenRequest, AccessTokenResponse, AuthorisePermitSuccess, Oauth2Error,
26 TokenRevokeRequest,
27 },
28 idm::server::IdmServerTransaction,
29 idm::serviceaccount::{DestroyApiTokenEvent, GenerateApiTokenEvent},
30 modify::{Modify, ModifyInvalid, ModifyList},
31 value::{OauthClaimMapJoin, PartialValue, Value},
32};
33
34use kanidmd_lib::prelude::*;
35
36#[cfg(feature = "dev-oauth2-device-flow")]
37use std::collections::BTreeSet;
38
39use super::QueryServerWriteV1;
40
41impl QueryServerWriteV1 {
42 #[instrument(level = "debug", skip_all)]
43 async fn modify_from_parts(
44 &self,
45 client_auth_info: ClientAuthInfo,
46 uuid_or_name: &str,
47 proto_ml: &ProtoModifyList,
48 filter: Filter<FilterInvalid>,
49 ) -> Result<(), OperationError> {
50 let ct = duration_from_epoch_now();
51 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
52
53 let ident = idms_prox_write
54 .validate_client_auth_info_to_ident(client_auth_info, ct)
55 .map_err(|e| {
56 error!(err = ?e, "Invalid identity");
57 e
58 })?;
59
60 let target_uuid = idms_prox_write
61 .qs_write
62 .name_to_uuid(uuid_or_name)
63 .map_err(|e| {
64 error!(err = ?e, "Error resolving id to target");
65 e
66 })?;
67
68 let mdf = match ModifyEvent::from_parts(
69 ident,
70 target_uuid,
71 proto_ml,
72 filter,
73 &mut idms_prox_write.qs_write,
74 ) {
75 Ok(m) => m,
76 Err(e) => {
77 error!(err=?e, "Failed to begin modify during modify_from_parts");
78 return Err(e);
79 }
80 };
81
82 trace!(?mdf, "Begin modify event");
83
84 idms_prox_write
85 .qs_write
86 .modify(&mdf)
87 .and_then(|_| idms_prox_write.commit().map(|_| ()))
88 }
89
90 #[instrument(level = "debug", skip_all)]
91 async fn modify_from_internal_parts(
92 &self,
93 client_auth_info: ClientAuthInfo,
94 uuid_or_name: &str,
95 ml: &ModifyList<ModifyInvalid>,
96 filter: Filter<FilterInvalid>,
97 ) -> Result<(), OperationError> {
98 let ct = duration_from_epoch_now();
99 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
100
101 let ident = idms_prox_write
102 .validate_client_auth_info_to_ident(client_auth_info, ct)
103 .map_err(|e| {
104 error!(err = ?e, "Invalid identity");
105 e
106 })?;
107
108 let target_uuid = idms_prox_write
109 .qs_write
110 .name_to_uuid(uuid_or_name)
111 .inspect_err(|err| {
112 error!(?err, "Error resolving id to target");
113 })?;
114
115 let f_uuid = filter_all!(f_eq(Attribute::Uuid, PartialValue::Uuid(target_uuid)));
116 let joined_filter = Filter::join_parts_and(f_uuid, filter);
118
119 let mdf = match ModifyEvent::from_internal_parts(
120 ident,
121 ml,
122 &joined_filter,
123 &idms_prox_write.qs_write,
124 ) {
125 Ok(m) => m,
126 Err(e) => {
127 error!(err = ?e, "Failed to begin modify during modify_from_internal_parts");
128 return Err(e);
129 }
130 };
131
132 trace!(?mdf, "Begin modify event");
133
134 idms_prox_write
135 .qs_write
136 .modify(&mdf)
137 .and_then(|_| idms_prox_write.commit().map(|_| ()))
138 }
139
140 #[instrument(
141 level = "info",
142 skip_all,
143 fields(uuid = ?eventid)
144 )]
145 pub async fn handle_create(
146 &self,
147 client_auth_info: ClientAuthInfo,
148 req: CreateRequest,
149 eventid: Uuid,
150 ) -> Result<(), OperationError> {
151 let ct = duration_from_epoch_now();
152 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
153
154 let ident = idms_prox_write
155 .validate_client_auth_info_to_ident(client_auth_info, ct)
156 .map_err(|e| {
157 error!(err = ?e, "Invalid identity");
158 e
159 })?;
160
161 let crt = match CreateEvent::from_message(ident, &req, &mut idms_prox_write.qs_write) {
162 Ok(c) => c,
163 Err(e) => {
164 admin_warn!(err = ?e, "Failed to begin create");
165 return Err(e);
166 }
167 };
168
169 trace!(?crt, "Begin create event");
170
171 idms_prox_write
172 .qs_write
173 .create(&crt)
174 .and_then(|_| idms_prox_write.commit())
175 }
176
177 #[instrument(
178 level = "info",
179 skip_all,
180 fields(uuid = ?eventid)
181 )]
182 pub async fn handle_modify(
183 &self,
184 client_auth_info: ClientAuthInfo,
185 req: ModifyRequest,
186 eventid: Uuid,
187 ) -> Result<(), OperationError> {
188 let ct = duration_from_epoch_now();
189 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
190 let ident = idms_prox_write
191 .validate_client_auth_info_to_ident(client_auth_info, ct)
192 .map_err(|e| {
193 error!(err = ?e, "Invalid identity");
194 e
195 })?;
196
197 let mdf = match ModifyEvent::from_message(ident, &req, &mut idms_prox_write.qs_write) {
198 Ok(m) => m,
199 Err(e) => {
200 error!(err = ?e, "Failed to begin modify during handle_modify");
201 return Err(e);
202 }
203 };
204
205 trace!(?mdf, "Begin modify event");
206
207 idms_prox_write
208 .qs_write
209 .modify(&mdf)
210 .and_then(|_| idms_prox_write.commit())
211 }
212
213 #[instrument(
214 level = "info",
215 skip_all,
216 fields(uuid = ?eventid)
217 )]
218 pub async fn handle_delete(
219 &self,
220 client_auth_info: ClientAuthInfo,
221 req: DeleteRequest,
222 eventid: Uuid,
223 ) -> Result<(), OperationError> {
224 let ct = duration_from_epoch_now();
225 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
226 let ident = idms_prox_write
227 .validate_client_auth_info_to_ident(client_auth_info, ct)
228 .map_err(|e| {
229 error!(err = ?e, "Invalid identity");
230 e
231 })?;
232 let del = match DeleteEvent::from_message(ident, &req, &mut idms_prox_write.qs_write) {
233 Ok(d) => d,
234 Err(e) => {
235 error!(err = ?e, "Failed to begin delete");
236 return Err(e);
237 }
238 };
239
240 trace!(?del, "Begin delete event");
241
242 idms_prox_write
243 .qs_write
244 .delete(&del)
245 .and_then(|_| idms_prox_write.commit())
246 }
247
248 #[instrument(
249 level = "info",
250 skip_all,
251 fields(uuid = ?eventid)
252 )]
253 pub async fn handle_internalpatch(
254 &self,
255 client_auth_info: ClientAuthInfo,
256 filter: Filter<FilterInvalid>,
257 update: ProtoEntry,
258 eventid: Uuid,
259 ) -> Result<(), OperationError> {
260 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(|e| {
266 error!(err = ?e, "Invalid identity");
267 e
268 })?;
269
270 let modlist =
272 ModifyList::from_patch(&update, &mut idms_prox_write.qs_write).map_err(|e| {
273 error!(err = ?e, "Invalid Patch Request");
274 e
275 })?;
276
277 let mdf =
278 ModifyEvent::from_internal_parts(ident, &modlist, &filter, &idms_prox_write.qs_write)
279 .map_err(|e| {
280 error!(err = ?e, "Failed to begin modify during handle_internalpatch");
281 e
282 })?;
283
284 trace!(?mdf, "Begin modify event");
285
286 idms_prox_write
287 .qs_write
288 .modify(&mdf)
289 .and_then(|_| idms_prox_write.commit())
290 }
291
292 #[instrument(
293 level = "info",
294 skip_all,
295 fields(uuid = ?eventid)
296 )]
297 pub async fn handle_internaldelete(
298 &self,
299 client_auth_info: ClientAuthInfo,
300 filter: Filter<FilterInvalid>,
301 eventid: Uuid,
302 ) -> Result<(), OperationError> {
303 let ct = duration_from_epoch_now();
304 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
305 let ident = idms_prox_write
306 .validate_client_auth_info_to_ident(client_auth_info, ct)
307 .map_err(|e| {
308 error!(err = ?e, "Invalid identity");
309 e
310 })?;
311 let del = match DeleteEvent::from_parts(ident, &filter, &mut idms_prox_write.qs_write) {
312 Ok(d) => d,
313 Err(e) => {
314 error!(err = ?e, "Failed to begin delete");
315 return Err(e);
316 }
317 };
318
319 trace!(?del, "Begin delete event");
320
321 idms_prox_write
322 .qs_write
323 .delete(&del)
324 .and_then(|_| idms_prox_write.commit().map(|_| ()))
325 }
326
327 #[instrument(
328 level = "info",
329 skip_all,
330 fields(uuid = ?eventid)
331 )]
332 pub async fn handle_reviverecycled(
333 &self,
334 client_auth_info: ClientAuthInfo,
335 filter: Filter<FilterInvalid>,
336 eventid: Uuid,
337 ) -> Result<(), OperationError> {
338 let ct = duration_from_epoch_now();
339 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
340 let ident = idms_prox_write
341 .validate_client_auth_info_to_ident(client_auth_info, ct)
342 .map_err(|e| {
343 error!(err = ?e, "Invalid identity");
344 e
345 })?;
346 let rev = match ReviveRecycledEvent::from_parts(ident, &filter, &idms_prox_write.qs_write) {
347 Ok(r) => r,
348 Err(e) => {
349 error!(err = ?e, "Failed to begin revive");
350 return Err(e);
351 }
352 };
353
354 trace!(?rev, "Begin revive event");
355
356 idms_prox_write
357 .qs_write
358 .revive_recycled(&rev)
359 .and_then(|_| idms_prox_write.commit().map(|_| ()))
360 }
361
362 #[instrument(
363 level = "info",
364 skip_all,
365 fields(uuid = ?eventid)
366 )]
367 pub async fn handle_service_account_credential_generate(
368 &self,
369 client_auth_info: ClientAuthInfo,
370 uuid_or_name: String,
371 eventid: Uuid,
372 ) -> Result<String, OperationError> {
373 let ct = duration_from_epoch_now();
374 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
375 let ident = idms_prox_write
376 .validate_client_auth_info_to_ident(client_auth_info, ct)
377 .map_err(|e| {
378 error!(err = ?e, "Invalid identity");
379 e
380 })?;
381
382 let target_uuid = idms_prox_write
388 .qs_write
389 .name_to_uuid(uuid_or_name.as_str())
390 .map_err(|e| {
391 error!(err = ?e, "Error resolving id to target");
392 e
393 })?;
394
395 let gpe = GeneratePasswordEvent::from_parts(ident, target_uuid).map_err(|e| {
396 error!(
397 err = ?e,
398 "Failed to begin handle_service_account_credential_generate",
399 );
400 e
401 })?;
402 idms_prox_write
403 .generate_service_account_password(&gpe)
404 .and_then(|r| idms_prox_write.commit().map(|_| r))
405 }
406
407 #[instrument(
408 level = "info",
409 skip_all,
410 fields(uuid = ?eventid)
411 )]
412 pub async fn handle_service_account_api_token_generate(
413 &self,
414 client_auth_info: ClientAuthInfo,
415 uuid_or_name: String,
416 label: String,
417 expiry: Option<OffsetDateTime>,
418 read_write: bool,
419 eventid: Uuid,
420 ) -> Result<String, OperationError> {
421 let ct = duration_from_epoch_now();
422 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
423 let ident = idms_prox_write
424 .validate_client_auth_info_to_ident(client_auth_info, ct)
425 .map_err(|e| {
426 error!(err = ?e, "Invalid identity");
427 e
428 })?;
429
430 let target = idms_prox_write
431 .qs_write
432 .name_to_uuid(uuid_or_name.as_str())
433 .map_err(|e| {
434 error!(err = ?e, "Error resolving id to target");
435 e
436 })?;
437
438 let gte = GenerateApiTokenEvent {
439 ident,
440 target,
441 label,
442 expiry,
443 read_write,
444 };
445
446 idms_prox_write
447 .service_account_generate_api_token(>e, ct)
448 .and_then(|r| idms_prox_write.commit().map(|_| r))
449 .map(|token| token.to_string())
450 }
451
452 #[instrument(
453 level = "info",
454 skip_all,
455 fields(uuid = ?eventid)
456 )]
457 pub async fn handle_service_account_api_token_destroy(
458 &self,
459 client_auth_info: ClientAuthInfo,
460 uuid_or_name: String,
461 token_id: Uuid,
462 eventid: Uuid,
463 ) -> Result<(), OperationError> {
464 let ct = duration_from_epoch_now();
465 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
466 let ident = idms_prox_write
467 .validate_client_auth_info_to_ident(client_auth_info, ct)
468 .map_err(|e| {
469 error!(err = ?e, "Invalid identity");
470 e
471 })?;
472
473 let target = idms_prox_write
474 .qs_write
475 .name_to_uuid(uuid_or_name.as_str())
476 .map_err(|e| {
477 error!(err = ?e, "Error resolving id to target");
478 e
479 })?;
480
481 let dte = DestroyApiTokenEvent {
482 ident,
483 target,
484 token_id,
485 };
486
487 idms_prox_write
488 .service_account_destroy_api_token(&dte)
489 .and_then(|r| idms_prox_write.commit().map(|_| r))
490 }
491
492 #[instrument(
493 level = "info",
494 skip_all,
495 fields(uuid = ?eventid)
496 )]
497 pub async fn handle_account_user_auth_token_destroy(
498 &self,
499 client_auth_info: ClientAuthInfo,
500 uuid_or_name: String,
501 token_id: Uuid,
502 eventid: Uuid,
503 ) -> Result<(), OperationError> {
504 let ct = duration_from_epoch_now();
505 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
506 let ident = idms_prox_write
507 .validate_client_auth_info_to_ident(client_auth_info, ct)
508 .map_err(|e| {
509 error!(err = ?e, "Invalid identity");
510 e
511 })?;
512
513 let target = idms_prox_write
514 .qs_write
515 .name_to_uuid(uuid_or_name.as_str())
516 .map_err(|e| {
517 error!(err = ?e, "Error resolving id to target");
518 e
519 })?;
520
521 let dte = DestroySessionTokenEvent {
522 ident,
523 target,
524 token_id,
525 };
526
527 idms_prox_write
528 .account_destroy_session_token(&dte)
529 .and_then(|r| idms_prox_write.commit().map(|_| r))
530 }
531
532 #[instrument(
533 level = "info",
534 skip_all,
535 fields(uuid = ?eventid)
536 )]
537 pub async fn handle_logout(
538 &self,
539 client_auth_info: ClientAuthInfo,
540 eventid: Uuid,
541 ) -> Result<(), OperationError> {
542 let ct = duration_from_epoch_now();
543 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
544
545 let validate_result =
547 idms_prox_write.validate_client_auth_info_to_ident(client_auth_info, ct);
548
549 let ident = match validate_result {
550 Ok(ident) => ident,
551 Err(OperationError::SessionExpired) | Err(OperationError::NotAuthenticated) => {
552 return Ok(())
553 }
554 Err(err) => {
555 error!(?err, "Invalid identity");
556 return Err(err);
557 }
558 };
559
560 if !ident.can_logout() {
561 info!("Ignoring request to logout session - these sessions are not recorded");
562 return Ok(());
563 };
564
565 let target = ident.get_uuid().ok_or_else(|| {
566 error!("Invalid identity - no uuid present");
567 OperationError::InvalidState
568 })?;
569
570 let token_id = ident.get_session_id();
571
572 let dte = DestroySessionTokenEvent {
573 ident,
574 target,
575 token_id,
576 };
577
578 idms_prox_write
579 .account_destroy_session_token(&dte)
580 .and_then(|r| idms_prox_write.commit().map(|_| r))
581 }
582
583 #[instrument(
584 level = "info",
585 skip_all,
586 fields(uuid = ?eventid)
587 )]
588 pub async fn handle_idmcredentialupdate(
589 &self,
590 client_auth_info: ClientAuthInfo,
591 uuid_or_name: String,
592 eventid: Uuid,
593 ) -> Result<(CUSessionToken, CUStatus), OperationError> {
594 let ct = duration_from_epoch_now();
595 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
596 let ident = idms_prox_write
597 .validate_client_auth_info_to_ident(client_auth_info, ct)
598 .map_err(|e| {
599 error!(err = ?e, "Invalid identity");
600 e
601 })?;
602
603 let target_uuid = idms_prox_write
604 .qs_write
605 .name_to_uuid(uuid_or_name.as_str())
606 .map_err(|e| {
607 error!(err = ?e, "Error resolving id to target");
608 e
609 })?;
610
611 idms_prox_write
612 .init_credential_update(&InitCredentialUpdateEvent::new(ident, target_uuid), ct)
613 .and_then(|tok| idms_prox_write.commit().map(|_| tok))
614 .map_err(|e| {
615 error!(
616 err = ?e,
617 "Failed to begin init_credential_update",
618 );
619 e
620 })
621 .map(|(tok, sta)| {
622 (
623 CUSessionToken {
624 token: tok.token_enc.to_string(),
625 },
626 sta.into(),
627 )
628 })
629 }
630
631 #[instrument(
632 level = "info",
633 skip_all,
634 fields(uuid = ?eventid),
635 )]
636 pub async fn handle_idmcredentialupdateintent(
637 &self,
638 client_auth_info: ClientAuthInfo,
639 uuid_or_name: String,
640 ttl: Option<Duration>,
641 eventid: Uuid,
642 ) -> Result<CUIntentToken, OperationError> {
643 let ct = duration_from_epoch_now();
644 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
645 let ident = idms_prox_write
646 .validate_client_auth_info_to_ident(client_auth_info, ct)
647 .map_err(|e| {
648 error!(err = ?e, "Invalid identity");
649 e
650 })?;
651
652 let target_uuid = idms_prox_write
653 .qs_write
654 .name_to_uuid(uuid_or_name.as_str())
655 .map_err(|e| {
656 error!(err = ?e, "Error resolving id to target");
657 e
658 })?;
659
660 idms_prox_write
661 .init_credential_update_intent(
662 &InitCredentialUpdateIntentEvent::new(ident, target_uuid, ttl),
663 ct,
664 )
665 .and_then(|tok| idms_prox_write.commit().map(|_| tok))
666 .map_err(|e| {
667 error!(
668 err = ?e,
669 "Failed to begin init_credential_update_intent",
670 );
671 e
672 })
673 .map(|tok| CUIntentToken {
674 token: tok.intent_id,
675 expiry_time: tok.expiry_time,
676 })
677 }
678
679 #[instrument(
680 level = "info",
681 skip_all,
682 fields(uuid = ?eventid)
683 )]
684 pub async fn handle_idmcredentialexchangeintent(
685 &self,
686 intent_id: String,
687 eventid: Uuid,
688 ) -> Result<(CUSessionToken, CUStatus), OperationError> {
689 let ct = duration_from_epoch_now();
690 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
691 let intent_token = CredentialUpdateIntentTokenExchange { intent_id };
692 idms_prox_write
694 .exchange_intent_credential_update(intent_token, ct)
695 .and_then(|tok| idms_prox_write.commit().map(|_| tok))
696 .map_err(|e| {
697 error!(
698 err = ?e,
699 "Failed to begin exchange_intent_credential_update",
700 );
701 e
702 })
703 .map(|(tok, sta)| {
704 (
705 CUSessionToken {
706 token: tok.token_enc.to_string(),
707 },
708 sta.into(),
709 )
710 })
711 }
712
713 #[instrument(
714 level = "info",
715 skip_all,
716 fields(uuid = ?eventid)
717 )]
718 pub async fn handle_idmcredentialupdatecommit(
719 &self,
720 session_token: CUSessionToken,
721 eventid: Uuid,
722 ) -> Result<(), OperationError> {
723 let session_token = JweCompact::from_str(session_token.token.as_str())
724 .map(|token_enc| CredentialUpdateSessionToken { token_enc })
725 .map_err(|err| {
726 error!(?err, "malformed token");
727 OperationError::InvalidRequestState
728 })?;
729
730 let ct = duration_from_epoch_now();
731 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
732
733 idms_prox_write
734 .commit_credential_update(&session_token, ct)
735 .and_then(|tok| idms_prox_write.commit().map(|_| tok))
736 .map_err(|e| {
737 error!(
738 err = ?e,
739 "Failed to begin commit_credential_update",
740 );
741 e
742 })
743 }
744
745 #[instrument(
746 level = "info",
747 skip_all,
748 fields(uuid = ?eventid)
749 )]
750 pub async fn handle_idmcredentialupdatecancel(
751 &self,
752 session_token: CUSessionToken,
753 eventid: Uuid,
754 ) -> Result<(), OperationError> {
755 let session_token = JweCompact::from_str(session_token.token.as_str())
756 .map(|token_enc| CredentialUpdateSessionToken { token_enc })
757 .map_err(|err| {
758 error!(?err, "malformed token");
759 OperationError::InvalidRequestState
760 })?;
761
762 let ct = duration_from_epoch_now();
763 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
764
765 idms_prox_write
766 .cancel_credential_update(&session_token, ct)
767 .and_then(|tok| idms_prox_write.commit().map(|_| tok))
768 .map_err(|e| {
769 error!(
770 err = ?e,
771 "Failed to begin commit_credential_cancel",
772 );
773 e
774 })
775 }
776
777 #[instrument(
778 level = "info",
779 skip_all,
780 fields(uuid = ?eventid)
781 )]
782 pub async fn handle_service_account_into_person(
783 &self,
784 client_auth_info: ClientAuthInfo,
785 uuid_or_name: String,
786 eventid: Uuid,
787 ) -> Result<(), OperationError> {
788 let ct = duration_from_epoch_now();
789 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
790 let ident = idms_prox_write
791 .validate_client_auth_info_to_ident(client_auth_info, ct)
792 .map_err(|e| {
793 error!(err = ?e, "Invalid identity");
794 e
795 })?;
796 let target_uuid = idms_prox_write
797 .qs_write
798 .name_to_uuid(uuid_or_name.as_str())
799 .map_err(|e| {
800 error!(err = ?e, "Error resolving id to target");
801 e
802 })?;
803
804 idms_prox_write
805 .service_account_into_person(&ident, target_uuid)
806 .and_then(|_| idms_prox_write.commit())
807 }
808
809 #[instrument(
810 level = "info",
811 skip_all,
812 fields(uuid = ?eventid)
813 )]
814 pub async fn handle_regenerateradius(
815 &self,
816 client_auth_info: ClientAuthInfo,
817 uuid_or_name: String,
818 eventid: Uuid,
819 ) -> Result<String, OperationError> {
820 let ct = duration_from_epoch_now();
821 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
822 let ident = idms_prox_write
823 .validate_client_auth_info_to_ident(client_auth_info, ct)
824 .map_err(|e| {
825 error!(err = ?e, "Invalid identity");
826 e
827 })?;
828
829 let target_uuid = idms_prox_write
830 .qs_write
831 .name_to_uuid(uuid_or_name.as_str())
832 .map_err(|e| {
833 error!(err = ?e, "Error resolving id to target");
834 e
835 })?;
836
837 let rrse = RegenerateRadiusSecretEvent::from_parts(
838 ident,
840 target_uuid,
841 )
842 .map_err(|e| {
843 error!(
844 err = ?e,
845 "Failed to begin idm_account_regenerate_radius",
846 );
847 e
848 })?;
849
850 idms_prox_write
851 .regenerate_radius_secret(&rrse)
852 .and_then(|r| idms_prox_write.commit().map(|_| r))
853 }
854
855 #[instrument(
856 level = "info",
857 skip_all,
858 fields(uuid = ?eventid)
859 )]
860 pub async fn handle_purgeattribute(
861 &self,
862 client_auth_info: ClientAuthInfo,
863 uuid_or_name: String,
864 attr: String,
865 filter: Filter<FilterInvalid>,
866 eventid: Uuid,
867 ) -> Result<(), OperationError> {
868 let ct = duration_from_epoch_now();
869 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
870 let ident = idms_prox_write
871 .validate_client_auth_info_to_ident(client_auth_info, ct)
872 .map_err(|e| {
873 error!(err = ?e, "Invalid identity");
874 e
875 })?;
876 let target_uuid = idms_prox_write
877 .qs_write
878 .name_to_uuid(uuid_or_name.as_str())
879 .map_err(|e| {
880 error!(err = ?e, "Error resolving id to target");
881 e
882 })?;
883
884 let target_attr = Attribute::from(attr.as_str());
885 let mdf = match ModifyEvent::from_target_uuid_attr_purge(
886 ident,
887 target_uuid,
888 target_attr,
889 filter,
890 &idms_prox_write.qs_write,
891 ) {
892 Ok(m) => m,
893 Err(e) => {
894 error!(err = ?e, "Failed to begin modify during purge attribute");
895 return Err(e);
896 }
897 };
898
899 trace!(?mdf, "Begin modify event");
900
901 idms_prox_write
902 .qs_write
903 .modify(&mdf)
904 .and_then(|_| idms_prox_write.commit().map(|_| ()))
905 }
906
907 #[instrument(
908 level = "info",
909 skip_all,
910 fields(uuid = ?eventid)
911 )]
912 pub async fn handle_removeattributevalues(
913 &self,
914 client_auth_info: ClientAuthInfo,
915 uuid_or_name: String,
916 attr: String,
917 values: Vec<String>,
918 filter: Filter<FilterInvalid>,
919 eventid: Uuid,
920 ) -> Result<(), OperationError> {
921 let ct = duration_from_epoch_now();
922 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
923 let ident = idms_prox_write
924 .validate_client_auth_info_to_ident(client_auth_info, ct)
925 .map_err(|e| {
926 error!(err = ?e, "Invalid identity");
927 e
928 })?;
929 let target_uuid = idms_prox_write
930 .qs_write
931 .name_to_uuid(uuid_or_name.as_str())
932 .map_err(|e| {
933 error!(err = ?e, "Error resolving id to target");
934 e
935 })?;
936
937 let proto_ml = ProtoModifyList::new_list(
938 values
939 .into_iter()
940 .map(|v| ProtoModify::Removed(attr.clone(), v))
941 .collect(),
942 );
943
944 let mdf = match ModifyEvent::from_parts(
945 ident,
946 target_uuid,
947 &proto_ml,
948 filter,
949 &mut idms_prox_write.qs_write,
950 ) {
951 Ok(m) => m,
952 Err(e) => {
953 error!(err = ?e, "Failed to begin modify");
954 return Err(e);
955 }
956 };
957
958 trace!(?mdf, "Begin modify event");
959
960 idms_prox_write
961 .qs_write
962 .modify(&mdf)
963 .and_then(|_| idms_prox_write.commit().map(|_| ()))
964 }
965
966 #[instrument(
967 level = "info",
968 name = "append_attribute",
969 skip_all,
970 fields(uuid = ?eventid)
971 )]
972 pub async fn handle_appendattribute(
973 &self,
974 client_auth_info: ClientAuthInfo,
975 uuid_or_name: String,
976 attr: String,
977 values: Vec<String>,
978 filter: Filter<FilterInvalid>,
979 eventid: Uuid,
980 ) -> Result<(), OperationError> {
981 let proto_ml = ProtoModifyList::new_list(
984 values
985 .into_iter()
986 .map(|v| ProtoModify::Present(attr.clone(), v))
987 .collect(),
988 );
989 self.modify_from_parts(client_auth_info, &uuid_or_name, &proto_ml, filter)
990 .await
991 }
992
993 #[instrument(
994 level = "info",
995 name = "set_attribute",
996 skip_all,
997 fields(uuid = ?eventid)
998 )]
999 pub async fn handle_setattribute(
1000 &self,
1001 client_auth_info: ClientAuthInfo,
1002 uuid_or_name: String,
1003 attr: String,
1004 values: Vec<String>,
1005 filter: Filter<FilterInvalid>,
1006 eventid: Uuid,
1007 ) -> Result<(), OperationError> {
1008 let proto_ml = ProtoModifyList::new_list(
1011 std::iter::once(ProtoModify::Purged(attr.clone()))
1012 .chain(
1013 values
1014 .into_iter()
1015 .map(|v| ProtoModify::Present(attr.clone(), v)),
1016 )
1017 .collect(),
1018 );
1019 self.modify_from_parts(client_auth_info, &uuid_or_name, &proto_ml, filter)
1020 .await
1021 }
1022
1023 #[instrument(
1024 level = "info",
1025 name = "ssh_key_create",
1026 skip_all,
1027 fields(uuid = ?eventid)
1028 )]
1029 pub async fn handle_sshkeycreate(
1030 &self,
1031 client_auth_info: ClientAuthInfo,
1032 uuid_or_name: String,
1033 tag: &str,
1034 key: &str,
1035 filter: Filter<FilterInvalid>,
1036 eventid: Uuid,
1037 ) -> Result<(), OperationError> {
1038 let v_sk = Value::new_sshkey_str(tag, key)?;
1039
1040 let ml = ModifyList::new_append(Attribute::SshPublicKey, v_sk);
1043
1044 self.modify_from_internal_parts(client_auth_info, &uuid_or_name, &ml, filter)
1045 .await
1046 }
1047
1048 #[instrument(
1049 level = "info",
1050 name = "idm_account_unix_extend",
1051 skip_all,
1052 fields(uuid = ?eventid)
1053 )]
1054 pub async fn handle_idmaccountunixextend(
1055 &self,
1056 client_auth_info: ClientAuthInfo,
1057 uuid_or_name: String,
1058 ux: AccountUnixExtend,
1059 eventid: Uuid,
1060 ) -> Result<(), OperationError> {
1061 let AccountUnixExtend { gidnumber, shell } = ux;
1062 let mods: Vec<_> = iter::once(Some(Modify::Present(
1065 Attribute::Class,
1066 EntryClass::PosixAccount.into(),
1067 )))
1068 .chain(iter::once(
1069 gidnumber
1070 .as_ref()
1071 .map(|_| Modify::Purged(Attribute::GidNumber)),
1072 ))
1073 .chain(iter::once(gidnumber.map(|n| {
1074 Modify::Present(Attribute::GidNumber, Value::new_uint32(n))
1075 })))
1076 .chain(iter::once(
1077 shell
1078 .as_ref()
1079 .map(|_| Modify::Purged(Attribute::LoginShell)),
1080 ))
1081 .chain(iter::once(shell.map(|s| {
1082 Modify::Present(Attribute::LoginShell, Value::new_iutf8(s.as_str()))
1083 })))
1084 .flatten()
1085 .collect();
1086
1087 let ml = ModifyList::new_list(mods);
1088
1089 let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Account.into()));
1090
1091 self.modify_from_internal_parts(client_auth_info, &uuid_or_name, &ml, filter)
1092 .await
1093 }
1094
1095 #[instrument(
1096 level = "info",
1097 name = "idm_group_unix_extend",
1098 skip_all,
1099 fields(uuid = ?eventid)
1100 )]
1101 pub async fn handle_idmgroupunixextend(
1102 &self,
1103 client_auth_info: ClientAuthInfo,
1104 uuid_or_name: String,
1105 gx: GroupUnixExtend,
1106 eventid: Uuid,
1107 ) -> Result<(), OperationError> {
1108 let gidnumber_mods = if let Some(gid) = gx.gidnumber {
1112 [
1113 Some(Modify::Purged(Attribute::GidNumber)),
1114 Some(Modify::Present(
1115 Attribute::GidNumber,
1116 Value::new_uint32(gid),
1117 )),
1118 ]
1119 } else {
1120 [None, None]
1121 };
1122 let mods: Vec<_> = iter::once(Some(Modify::Present(
1123 Attribute::Class,
1124 EntryClass::PosixGroup.into(),
1125 )))
1126 .chain(gidnumber_mods)
1127 .flatten()
1128 .collect();
1129
1130 let ml = ModifyList::new_list(mods);
1131
1132 let filter = filter_all!(f_eq(Attribute::Class, EntryClass::Group.into()));
1133
1134 self.modify_from_internal_parts(client_auth_info, &uuid_or_name, &ml, filter)
1135 .await
1136 }
1137
1138 #[instrument(
1139 level = "info",
1140 skip_all,
1141 fields(uuid = ?eventid)
1142 )]
1143 pub async fn handle_idmaccountunixsetcred(
1144 &self,
1145 client_auth_info: ClientAuthInfo,
1146 uuid_or_name: String,
1147 cred: String,
1148 eventid: Uuid,
1149 ) -> Result<(), OperationError> {
1150 let ct = duration_from_epoch_now();
1151 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1152 let ident = idms_prox_write
1153 .validate_client_auth_info_to_ident(client_auth_info, ct)
1154 .map_err(|e| {
1155 error!(err = ?e, "Invalid identity");
1156 e
1157 })?;
1158
1159 let target_uuid = Uuid::parse_str(uuid_or_name.as_str()).or_else(|_| {
1160 idms_prox_write
1161 .qs_write
1162 .name_to_uuid(uuid_or_name.as_str())
1163 .inspect_err(|err| {
1164 info!(?err, "Error resolving as gidnumber continuing ...");
1165 })
1166 })?;
1167
1168 let upce = UnixPasswordChangeEvent::from_parts(
1169 ident,
1171 target_uuid,
1172 cred,
1173 )
1174 .map_err(|e| {
1175 error!(err = ?e, "Failed to begin UnixPasswordChangeEvent");
1176 e
1177 })?;
1178 idms_prox_write
1179 .set_unix_account_password(&upce)
1180 .and_then(|_| idms_prox_write.commit())
1181 .map(|_| ())
1182 }
1183
1184 #[instrument(level = "debug", skip_all)]
1185 pub async fn handle_image_update(
1186 &self,
1187 client_auth_info: ClientAuthInfo,
1188 request_filter: Filter<FilterInvalid>,
1189 image: Option<ImageValue>,
1190 ) -> Result<(), OperationError> {
1191 let ct = duration_from_epoch_now();
1192 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1193
1194 let ident = idms_prox_write
1195 .validate_client_auth_info_to_ident(client_auth_info, ct)
1196 .inspect_err(|err| {
1197 error!(?err, "Invalid identity in handle_image_update");
1198 })?;
1199
1200 let modlist = if let Some(image) = image {
1201 ModifyList::new_purge_and_set(Attribute::Image, Value::Image(image))
1202 } else {
1203 ModifyList::new_purge(Attribute::Image)
1204 };
1205
1206 let mdf = ModifyEvent::from_internal_parts(
1207 ident,
1208 &modlist,
1209 &request_filter,
1210 &idms_prox_write.qs_write,
1211 )
1212 .inspect_err(|err| {
1213 error!(?err, "Failed to begin modify during handle_image_update");
1214 })?;
1215
1216 idms_prox_write
1217 .qs_write
1218 .modify(&mdf)
1219 .and_then(|_| idms_prox_write.commit().map(|_| ()))
1220 }
1221
1222 #[instrument(
1223 level = "info",
1224 skip_all,
1225 fields(uuid = ?eventid)
1226 )]
1227 pub async fn handle_oauth2_scopemap_update(
1228 &self,
1229 client_auth_info: ClientAuthInfo,
1230 group: String,
1231 scopes: Vec<String>,
1232 filter: Filter<FilterInvalid>,
1233 eventid: Uuid,
1234 ) -> Result<(), OperationError> {
1235 let ct = duration_from_epoch_now();
1238 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1239
1240 let ident = idms_prox_write
1241 .validate_client_auth_info_to_ident(client_auth_info, ct)
1242 .map_err(|e| {
1243 error!(err = ?e, "Invalid identity");
1244 e
1245 })?;
1246
1247 let group_uuid = idms_prox_write
1248 .qs_write
1249 .name_to_uuid(group.as_str())
1250 .map_err(|e| {
1251 error!(err = ?e, "Error resolving group name to target");
1252 e
1253 })?;
1254
1255 let ml = ModifyList::new_append(
1256 Attribute::OAuth2RsScopeMap,
1257 Value::new_oauthscopemap(group_uuid, scopes.into_iter().collect()).ok_or_else(
1258 || OperationError::InvalidAttribute("Invalid Oauth Scope Map syntax".to_string()),
1259 )?,
1260 );
1261
1262 let mdf = match ModifyEvent::from_internal_parts(
1263 ident,
1264 &ml,
1265 &filter,
1266 &idms_prox_write.qs_write,
1267 ) {
1268 Ok(m) => m,
1269 Err(e) => {
1270 error!(err = ?e, "Failed to begin modify");
1271 return Err(e);
1272 }
1273 };
1274
1275 trace!(?mdf, "Begin modify event");
1276
1277 idms_prox_write
1278 .qs_write
1279 .modify(&mdf)
1280 .and_then(|_| idms_prox_write.commit().map(|_| ()))
1281 }
1282
1283 #[instrument(
1284 level = "info",
1285 skip_all,
1286 fields(uuid = ?eventid)
1287 )]
1288 pub async fn handle_oauth2_scopemap_delete(
1289 &self,
1290 client_auth_info: ClientAuthInfo,
1291 group: String,
1292 filter: Filter<FilterInvalid>,
1293 eventid: Uuid,
1294 ) -> Result<(), OperationError> {
1295 let ct = duration_from_epoch_now();
1296 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1297
1298 let ident = idms_prox_write
1299 .validate_client_auth_info_to_ident(client_auth_info, ct)
1300 .map_err(|e| {
1301 error!(err = ?e, "Invalid identity");
1302 e
1303 })?;
1304
1305 let group_uuid = idms_prox_write
1306 .qs_write
1307 .name_to_uuid(group.as_str())
1308 .map_err(|e| {
1309 error!(err = ?e, "Error resolving group name to target");
1310 e
1311 })?;
1312
1313 let ml =
1314 ModifyList::new_remove(Attribute::OAuth2RsScopeMap, PartialValue::Refer(group_uuid));
1315
1316 let mdf = match ModifyEvent::from_internal_parts(
1317 ident,
1318 &ml,
1319 &filter,
1320 &idms_prox_write.qs_write,
1321 ) {
1322 Ok(m) => m,
1323 Err(e) => {
1324 error!(err = ?e, "Failed to begin modify");
1325 return Err(e);
1326 }
1327 };
1328
1329 trace!(?mdf, "Begin modify event");
1330
1331 idms_prox_write
1332 .qs_write
1333 .modify(&mdf)
1334 .and_then(|_| idms_prox_write.commit().map(|_| ()))
1335 }
1336
1337 #[instrument(
1338 level = "info",
1339 skip_all,
1340 fields(uuid = ?eventid)
1341 )]
1342 pub async fn handle_oauth2_claimmap_update(
1343 &self,
1344 client_auth_info: ClientAuthInfo,
1345 claim_name: String,
1346 group: String,
1347 claims: Vec<String>,
1348 filter: Filter<FilterInvalid>,
1349 eventid: Uuid,
1350 ) -> Result<(), OperationError> {
1351 let ct = duration_from_epoch_now();
1354 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1355
1356 let ident = idms_prox_write
1357 .validate_client_auth_info_to_ident(client_auth_info, ct)
1358 .map_err(|e| {
1359 error!(err = ?e, "Invalid identity");
1360 e
1361 })?;
1362
1363 let group_uuid = idms_prox_write
1364 .qs_write
1365 .name_to_uuid(group.as_str())
1366 .map_err(|e| {
1367 error!(err = ?e, "Error resolving group name to target");
1368 e
1369 })?;
1370
1371 let ml = ModifyList::new_append(
1372 Attribute::OAuth2RsClaimMap,
1373 Value::new_oauthclaimmap(claim_name, group_uuid, claims.into_iter().collect())
1374 .ok_or_else(|| {
1375 OperationError::InvalidAttribute("Invalid Oauth Claim Map syntax".to_string())
1376 })?,
1377 );
1378
1379 let mdf = match ModifyEvent::from_internal_parts(
1380 ident,
1381 &ml,
1382 &filter,
1383 &idms_prox_write.qs_write,
1384 ) {
1385 Ok(m) => m,
1386 Err(e) => {
1387 error!(err = ?e, "Failed to begin modify");
1388 return Err(e);
1389 }
1390 };
1391
1392 trace!(?mdf, "Begin modify event");
1393
1394 idms_prox_write
1395 .qs_write
1396 .modify(&mdf)
1397 .and_then(|_| idms_prox_write.commit().map(|_| ()))
1398 }
1399
1400 #[instrument(
1401 level = "info",
1402 skip_all,
1403 fields(uuid = ?eventid)
1404 )]
1405 pub async fn handle_oauth2_claimmap_join_update(
1406 &self,
1407 client_auth_info: ClientAuthInfo,
1408 claim_name: String,
1409 join: ProtoOauth2ClaimMapJoin,
1410 filter: Filter<FilterInvalid>,
1411 eventid: Uuid,
1412 ) -> Result<(), OperationError> {
1413 let ct = duration_from_epoch_now();
1416 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1417
1418 let ident = idms_prox_write
1419 .validate_client_auth_info_to_ident(client_auth_info, ct)
1420 .map_err(|e| {
1421 error!(err = ?e, "Invalid identity");
1422 e
1423 })?;
1424
1425 let join = match join {
1426 ProtoOauth2ClaimMapJoin::Csv => OauthClaimMapJoin::CommaSeparatedValue,
1427 ProtoOauth2ClaimMapJoin::Ssv => OauthClaimMapJoin::SpaceSeparatedValue,
1428 ProtoOauth2ClaimMapJoin::Array => OauthClaimMapJoin::JsonArray,
1429 };
1430
1431 let ml = ModifyList::new_append(
1432 Attribute::OAuth2RsClaimMap,
1433 Value::OauthClaimMap(claim_name, join),
1434 );
1435
1436 let mdf = match ModifyEvent::from_internal_parts(
1437 ident,
1438 &ml,
1439 &filter,
1440 &idms_prox_write.qs_write,
1441 ) {
1442 Ok(m) => m,
1443 Err(e) => {
1444 error!(err = ?e, "Failed to begin modify");
1445 return Err(e);
1446 }
1447 };
1448
1449 trace!(?mdf, "Begin modify event");
1450
1451 idms_prox_write
1452 .qs_write
1453 .modify(&mdf)
1454 .and_then(|_| idms_prox_write.commit().map(|_| ()))
1455 }
1456
1457 #[instrument(
1458 level = "info",
1459 skip_all,
1460 fields(uuid = ?eventid)
1461 )]
1462 pub async fn handle_oauth2_claimmap_delete(
1463 &self,
1464 client_auth_info: ClientAuthInfo,
1465 claim_name: String,
1466 group: String,
1467 filter: Filter<FilterInvalid>,
1468 eventid: Uuid,
1469 ) -> Result<(), OperationError> {
1470 let ct = duration_from_epoch_now();
1471 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1472
1473 let ident = idms_prox_write
1474 .validate_client_auth_info_to_ident(client_auth_info, ct)
1475 .map_err(|e| {
1476 error!(err = ?e, "Invalid identity");
1477 e
1478 })?;
1479
1480 let group_uuid = idms_prox_write
1481 .qs_write
1482 .name_to_uuid(group.as_str())
1483 .map_err(|e| {
1484 error!(err = ?e, "Error resolving group name to target");
1485 e
1486 })?;
1487
1488 let ml = ModifyList::new_remove(
1489 Attribute::OAuth2RsClaimMap,
1490 PartialValue::OauthClaim(claim_name, group_uuid),
1491 );
1492
1493 let mdf = match ModifyEvent::from_internal_parts(
1494 ident,
1495 &ml,
1496 &filter,
1497 &idms_prox_write.qs_write,
1498 ) {
1499 Ok(m) => m,
1500 Err(e) => {
1501 error!(err = ?e, "Failed to begin modify");
1502 return Err(e);
1503 }
1504 };
1505
1506 trace!(?mdf, "Begin modify event");
1507
1508 idms_prox_write
1509 .qs_write
1510 .modify(&mdf)
1511 .and_then(|_| idms_prox_write.commit().map(|_| ()))
1512 }
1513
1514 #[instrument(
1515 level = "info",
1516 skip_all,
1517 fields(uuid = ?eventid)
1518 )]
1519 pub async fn handle_oauth2_sup_scopemap_update(
1520 &self,
1521 client_auth_info: ClientAuthInfo,
1522 group: String,
1523 scopes: Vec<String>,
1524 filter: Filter<FilterInvalid>,
1525 eventid: Uuid,
1526 ) -> Result<(), OperationError> {
1527 let ct = duration_from_epoch_now();
1530 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1531
1532 let ident = idms_prox_write
1533 .validate_client_auth_info_to_ident(client_auth_info, ct)
1534 .map_err(|e| {
1535 error!(err = ?e, "Invalid identity");
1536 e
1537 })?;
1538
1539 let group_uuid = idms_prox_write
1540 .qs_write
1541 .name_to_uuid(group.as_str())
1542 .map_err(|e| {
1543 error!(err = ?e, "Error resolving group name to target");
1544 e
1545 })?;
1546
1547 let ml = ModifyList::new_append(
1548 Attribute::OAuth2RsSupScopeMap,
1549 Value::new_oauthscopemap(group_uuid, scopes.into_iter().collect()).ok_or_else(
1550 || OperationError::InvalidAttribute("Invalid Oauth Scope Map syntax".to_string()),
1551 )?,
1552 );
1553
1554 let mdf = match ModifyEvent::from_internal_parts(
1555 ident,
1556 &ml,
1557 &filter,
1558 &idms_prox_write.qs_write,
1559 ) {
1560 Ok(m) => m,
1561 Err(e) => {
1562 error!(err = ?e, "Failed to begin modify");
1563 return Err(e);
1564 }
1565 };
1566
1567 trace!(?mdf, "Begin modify event");
1568
1569 idms_prox_write
1570 .qs_write
1571 .modify(&mdf)
1572 .and_then(|_| idms_prox_write.commit().map(|_| ()))
1573 }
1574
1575 #[instrument(
1576 level = "info",
1577 skip_all,
1578 fields(uuid = ?eventid)
1579 )]
1580 pub async fn handle_oauth2_sup_scopemap_delete(
1581 &self,
1582 client_auth_info: ClientAuthInfo,
1583 group: String,
1584 filter: Filter<FilterInvalid>,
1585 eventid: Uuid,
1586 ) -> Result<(), OperationError> {
1587 let ct = duration_from_epoch_now();
1588 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1589
1590 let ident = idms_prox_write
1591 .validate_client_auth_info_to_ident(client_auth_info, ct)
1592 .map_err(|e| {
1593 error!(err = ?e, "Invalid identity");
1594 e
1595 })?;
1596
1597 let group_uuid = idms_prox_write
1598 .qs_write
1599 .name_to_uuid(group.as_str())
1600 .map_err(|e| {
1601 error!(err = ?e, "Error resolving group name to target");
1602 e
1603 })?;
1604
1605 let ml = ModifyList::new_remove(
1606 Attribute::OAuth2RsSupScopeMap,
1607 PartialValue::Refer(group_uuid),
1608 );
1609
1610 let mdf = match ModifyEvent::from_internal_parts(
1611 ident,
1612 &ml,
1613 &filter,
1614 &idms_prox_write.qs_write,
1615 ) {
1616 Ok(m) => m,
1617 Err(e) => {
1618 error!(err = ?e, "Failed to begin modify");
1619 return Err(e);
1620 }
1621 };
1622
1623 trace!(?mdf, "Begin modify event");
1624
1625 idms_prox_write
1626 .qs_write
1627 .modify(&mdf)
1628 .and_then(|_| idms_prox_write.commit().map(|_| ()))
1629 }
1630
1631 #[instrument(
1632 level = "info",
1633 skip_all,
1634 fields(uuid = ?eventid)
1635 )]
1636 pub async fn handle_oauth2_authorise_permit(
1637 &self,
1638 client_auth_info: ClientAuthInfo,
1639 consent_req: String,
1640 eventid: Uuid,
1641 ) -> Result<AuthorisePermitSuccess, OperationError> {
1642 let ct = duration_from_epoch_now();
1643 let mut idms_prox_write = self.idms.proxy_write(ct).await?;
1644
1645 let ident = idms_prox_write
1646 .validate_client_auth_info_to_ident(client_auth_info, ct)
1647 .inspect_err(|err| {
1648 error!(?err, "Invalid identity");
1649 })?;
1650
1651 idms_prox_write
1652 .check_oauth2_authorise_permit(&ident, &consent_req, ct)
1653 .and_then(|r| idms_prox_write.commit().map(|()| r))
1654 }
1655
1656 #[instrument(
1657 level = "info",
1658 skip_all,
1659 fields(uuid = ?eventid)
1660 )]
1661 pub async fn handle_oauth2_token_exchange(
1662 &self,
1663 client_auth_info: ClientAuthInfo,
1664 token_req: AccessTokenRequest,
1665 eventid: Uuid,
1666 ) -> Result<AccessTokenResponse, Oauth2Error> {
1667 let ct = duration_from_epoch_now();
1668 let mut idms_prox_write = self
1669 .idms
1670 .proxy_write(ct)
1671 .await
1672 .map_err(Oauth2Error::ServerError)?;
1673 let resp = idms_prox_write.check_oauth2_token_exchange(&client_auth_info, &token_req, ct);
1675
1676 match &resp {
1677 Err(Oauth2Error::InvalidGrant) | Ok(_) => {
1678 idms_prox_write.commit().map_err(Oauth2Error::ServerError)?;
1679 }
1680 _ => {}
1681 };
1682
1683 resp
1684 }
1685
1686 #[instrument(
1687 level = "info",
1688 skip_all,
1689 fields(uuid = ?eventid)
1690 )]
1691 pub async fn handle_oauth2_token_revoke(
1692 &self,
1693 client_auth_info: ClientAuthInfo,
1694 intr_req: TokenRevokeRequest,
1695 eventid: Uuid,
1696 ) -> Result<(), Oauth2Error> {
1697 let ct = duration_from_epoch_now();
1698 let mut idms_prox_write = self
1699 .idms
1700 .proxy_write(ct)
1701 .await
1702 .map_err(Oauth2Error::ServerError)?;
1703 idms_prox_write
1704 .oauth2_token_revoke(&client_auth_info, &intr_req, ct)
1705 .and_then(|()| idms_prox_write.commit().map_err(Oauth2Error::ServerError))
1706 }
1707
1708 #[cfg(feature = "dev-oauth2-device-flow")]
1709 pub async fn handle_oauth2_device_flow_start(
1710 &self,
1711 client_auth_info: ClientAuthInfo,
1712 client_id: &str,
1713 scope: &Option<BTreeSet<String>>,
1714 eventid: Uuid,
1715 ) -> Result<kanidm_proto::oauth2::DeviceAuthorizationResponse, Oauth2Error> {
1716 let ct = duration_from_epoch_now();
1717 let mut idms_prox_write = self
1718 .idms
1719 .proxy_write(ct)
1720 .await
1721 .map_err(Oauth2Error::ServerError)?;
1722 idms_prox_write
1723 .handle_oauth2_start_device_flow(client_auth_info, client_id, scope, eventid)
1724 .and_then(|res| {
1725 idms_prox_write.commit().map_err(Oauth2Error::ServerError)?;
1726 Ok(res)
1727 })
1728 }
1729}