1use std::convert::TryFrom;
2use std::fs;
3use std::net::IpAddr;
4use std::path::{Path, PathBuf};
5use std::str::FromStr;
6
7use kanidm_proto::internal::{
8 ApiToken, AppLink, BackupCodesView, CURequest, CUSessionToken, CUStatus, CredentialStatus,
9 IdentifyUserRequest, IdentifyUserResponse, ImageValue, OperationError, RadiusAuthToken,
10 SearchRequest, SearchResponse, UserAuthToken,
11};
12use kanidm_proto::oauth2::OidcWebfingerResponse;
13use kanidm_proto::v1::{
14 AuthIssueSession, AuthRequest, Entry as ProtoEntry, UatStatus, UnixGroupToken, UnixUserToken,
15 WhoamiResponse,
16};
17use kanidmd_lib::idm::identityverification::{
18 IdentifyUserDisplayCodeEvent, IdentifyUserStartEvent, IdentifyUserSubmitCodeEvent,
19};
20use ldap3_proto::simple::*;
21use regex::Regex;
22use tracing::{error, info, instrument, trace};
23use uuid::Uuid;
24
25use compact_jwt::{JweCompact, Jwk, JwsCompact};
26
27use kanidmd_lib::be::BackendTransaction;
28use kanidmd_lib::prelude::*;
29use kanidmd_lib::{
30 event::{OnlineBackupEvent, SearchEvent, SearchResult, WhoamiResult},
31 filter::{Filter, FilterInvalid},
32 idm::account::ListUserAuthTokenEvent,
33 idm::credupdatesession::CredentialUpdateSessionToken,
34 idm::event::{
35 AuthEvent, AuthResult, CredentialStatusEvent, RadiusAuthTokenEvent, ReadBackupCodeEvent,
36 UnixGroupTokenEvent, UnixUserAuthEvent, UnixUserTokenEvent,
37 },
38 idm::ldap::{LdapBoundToken, LdapResponseState},
39 idm::oauth2::{
40 AccessTokenIntrospectRequest, AccessTokenIntrospectResponse, AuthorisationRequest,
41 AuthoriseReject, AuthoriseResponse, JwkKeySet, Oauth2Error, Oauth2Rfc8414MetadataResponse,
42 OidcDiscoveryResponse, OidcToken,
43 },
44 idm::server::{DomainInfoRead, IdmServerTransaction},
45 idm::serviceaccount::ListApiTokenEvent,
46 idm::ClientAuthInfo,
47};
48
49use super::QueryServerReadV1;
50
51impl QueryServerReadV1 {
54 #[instrument(
64 level = "info",
65 name = "search",
66 skip_all,
67 fields(uuid = ?eventid)
68 )]
69 pub async fn handle_search(
70 &self,
71 client_auth_info: ClientAuthInfo,
72 req: SearchRequest,
73 eventid: Uuid,
74 ) -> Result<SearchResponse, OperationError> {
75 let ct = duration_from_epoch_now();
77 let mut idms_prox_read = self.idms.proxy_read().await?;
78 let ident = idms_prox_read
79 .validate_client_auth_info_to_ident(client_auth_info, ct)
80 .map_err(|e| {
81 error!(?e, "Invalid identity");
82 e
83 })?;
84
85 let search =
87 SearchEvent::from_message(ident, &req, &mut idms_prox_read.qs_read).map_err(|e| {
88 error!(?e, "Failed to begin search");
89 e
90 })?;
91
92 trace!(?search, "Begin event");
93
94 let entries = idms_prox_read.qs_read.search_ext(&search)?;
95
96 SearchResult::new(&mut idms_prox_read.qs_read, &entries).map(SearchResult::response)
97 }
98
99 #[instrument(
100 level = "info",
101 name = "auth",
102 skip_all,
103 fields(uuid = ?eventid)
104 )]
105 pub async fn handle_auth(
106 &self,
107 sessionid: Option<Uuid>,
108 req: AuthRequest,
109 eventid: Uuid,
110 client_auth_info: ClientAuthInfo,
111 ) -> Result<AuthResult, OperationError> {
112 let ct = duration_from_epoch_now();
117 let mut idm_auth = self.idms.auth().await?;
118 security_info!(?sessionid, ?req, "Begin auth event");
119
120 let ae = AuthEvent::from_message(sessionid, req).map_err(|e| {
124 error!(err = ?e, "Failed to parse AuthEvent");
125 e
126 })?;
127
128 idm_auth.expire_auth_sessions(ct).await;
132
133 let res = idm_auth
136 .auth(&ae, ct, client_auth_info)
137 .await
138 .and_then(|r| idm_auth.commit().map(|_| r));
139
140 security_info!(?res, "Sending auth result");
141
142 res
143 }
144
145 #[instrument(
146 level = "info",
147 name = "reauth",
148 skip_all,
149 fields(uuid = ?eventid)
150 )]
151 pub async fn handle_reauth(
152 &self,
153 client_auth_info: ClientAuthInfo,
154 issue: AuthIssueSession,
155 eventid: Uuid,
156 ) -> Result<AuthResult, OperationError> {
157 let ct = duration_from_epoch_now();
158 let mut idm_auth = self.idms.auth().await?;
159 security_info!("Begin reauth event");
160
161 let ident = idm_auth
162 .validate_client_auth_info_to_ident(client_auth_info.clone(), ct)
163 .map_err(|e| {
164 error!(?e, "Invalid identity");
165 e
166 })?;
167
168 idm_auth.expire_auth_sessions(ct).await;
172
173 let res = idm_auth
176 .reauth_init(ident, issue, ct, client_auth_info)
177 .await
178 .and_then(|r| idm_auth.commit().map(|_| r));
179
180 security_info!(?res, "Sending reauth result");
181
182 res
183 }
184
185 #[instrument(
186 level = "info",
187 name = "online_backup",
188 skip_all,
189 fields(uuid = ?msg.eventid)
190 )]
191 pub async fn handle_online_backup(
192 &self,
193 msg: OnlineBackupEvent,
194 outpath: &Path,
195 versions: usize,
196 ) -> Result<(), OperationError> {
197 trace!(eventid = ?msg.eventid, "Begin online backup event");
198
199 let now = time::OffsetDateTime::now_utc();
200
201 #[allow(clippy::unwrap_used)]
202 let timestamp = now.format(&Rfc3339).unwrap();
203 let dest_file = outpath.join(format!("backup-{}.json", timestamp));
204
205 if dest_file.exists() {
206 error!(
207 "Online backup file {} already exists, will not overwrite it.",
208 dest_file.display()
209 );
210 return Err(OperationError::InvalidState);
211 }
212
213 {
215 let mut idms_prox_read = self.idms.proxy_read().await?;
216 idms_prox_read
217 .qs_read
218 .get_be_txn()
219 .backup(&dest_file)
220 .map(|()| {
221 info!("Online backup created {} successfully", dest_file.display());
222 })
223 .map_err(|e| {
224 error!(
225 "Online backup failed to create {}: {:?}",
226 dest_file.display(),
227 e
228 );
229 OperationError::InvalidState
230 })?;
231 }
232
233 let re = Regex::new(r"^backup-\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?Z\.json$")
235 .map_err(|error| {
236 error!(
237 "Failed to parse regexp for online backup files: {:?}",
238 error
239 );
240 OperationError::InvalidState
241 })?;
242
243 let mut backup_file_list: Vec<PathBuf> = Vec::new();
245 match fs::read_dir(outpath) {
247 Ok(rd) => {
248 for entry in rd {
249 let pb = entry
251 .map_err(|e| {
252 error!(?e, "Pathbuf access");
253 OperationError::InvalidState
254 })?
255 .path();
256
257 if !pb.is_file() {
259 continue;
260 }
261
262 let file_name = pb.file_name().and_then(|f| f.to_str()).ok_or_else(|| {
264 error!("filename is invalid");
265 OperationError::InvalidState
266 })?;
267 if re.is_match(file_name) {
269 backup_file_list.push(pb.clone());
270 }
271 }
272 }
273 Err(e) => {
274 error!(
275 "Online backup cleanup error read dir {}: {}",
276 outpath.display(),
277 e
278 );
279 return Err(OperationError::InvalidState);
280 }
281 }
282
283 backup_file_list.sort();
285
286 if backup_file_list.len() > versions {
292 let x = backup_file_list.len() - versions;
293 info!(
294 "Online backup cleanup found {} versions, should keep {}, will remove {}",
295 backup_file_list.len(),
296 versions,
297 x
298 );
299 backup_file_list.truncate(x);
300
301 for file in backup_file_list {
303 debug!("Online backup cleanup: removing {:?}", &file);
304 match fs::remove_file(&file) {
305 Ok(_) => {}
306 Err(e) => {
307 error!(
308 "Online backup cleanup failed to remove file {:?}: {:?}",
309 file, e
310 )
311 }
312 };
313 }
314 } else {
315 debug!("Online backup cleanup had no files to remove");
316 };
317
318 Ok(())
319 }
320
321 #[instrument(
322 level = "info",
323 name = "whoami",
324 skip_all,
325 fields(uuid = ?eventid)
326 )]
327 pub async fn handle_whoami(
328 &self,
329 client_auth_info: ClientAuthInfo,
330 eventid: Uuid,
331 ) -> Result<WhoamiResponse, OperationError> {
332 let ct = duration_from_epoch_now();
334 let mut idms_prox_read = self.idms.proxy_read().await?;
335 let ident = idms_prox_read
343 .validate_client_auth_info_to_ident(client_auth_info, ct)
344 .map_err(|e| {
345 error!(?e, "Invalid identity");
346 e
347 })?;
348 let srch =
349 SearchEvent::from_whoami_request(ident, &idms_prox_read.qs_read).map_err(|e| {
350 error!(?e, "Failed to begin whoami");
351 e
352 })?;
353
354 trace!(search = ?srch, "Begin event");
355
356 let mut entries = idms_prox_read.qs_read.search_ext(&srch)?;
357
358 match entries.pop() {
359 Some(e) if entries.is_empty() => {
360 WhoamiResult::new(&mut idms_prox_read.qs_read, &e).map(WhoamiResult::response)
361 }
362 Some(_) => Err(OperationError::InvalidState), _ => Err(OperationError::NoMatchingEntries),
364 }
365 }
366
367 #[instrument(
368 level = "info",
369 name = "whoami_uat",
370 skip_all,
371 fields(uuid = ?eventid)
372 )]
373 pub async fn handle_whoami_uat(
374 &self,
375 client_auth_info: ClientAuthInfo,
376 eventid: Uuid,
377 ) -> Result<UserAuthToken, OperationError> {
378 let ct = duration_from_epoch_now();
379 let mut idms_prox_read = self.idms.proxy_read().await?;
380 idms_prox_read
388 .validate_client_auth_info_to_uat(client_auth_info, ct)
389 .map_err(|e| {
390 error!(?e, "Invalid identity");
391 e
392 })
393 }
394
395 #[instrument(level = "debug", skip_all)]
396 pub async fn handle_oauth2_rs_image_get_image(
398 &self,
399 client_auth_info: ClientAuthInfo,
400 rs: Filter<FilterInvalid>,
401 ) -> Result<Option<ImageValue>, OperationError> {
402 let mut idms_prox_read = self.idms.proxy_read().await?;
403 let ct = duration_from_epoch_now();
404
405 let ident = idms_prox_read
406 .validate_client_auth_info_to_ident(client_auth_info, ct)
407 .map_err(|e| {
408 error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_get_image");
409 e
410 })?;
411 let attrs = vec![Attribute::Image.to_string()];
412
413 let search = SearchEvent::from_internal_message(
414 ident,
415 &rs,
416 Some(attrs.as_slice()),
417 &mut idms_prox_read.qs_read,
418 )?;
419
420 let entries = idms_prox_read.qs_read.search(&search)?;
421 Ok(entries
422 .first()
423 .and_then(|entry| entry.get_ava_single_image(Attribute::Image)))
424 }
425
426 #[instrument(
427 level = "info",
428 skip_all,
429 fields(uuid = ?eventid)
430 )]
431 pub async fn handle_internalsearch(
432 &self,
433 client_auth_info: ClientAuthInfo,
434 filter: Filter<FilterInvalid>,
435 attrs: Option<Vec<String>>,
436 eventid: Uuid,
437 ) -> Result<Vec<ProtoEntry>, OperationError> {
438 let ct = duration_from_epoch_now();
439 let mut idms_prox_read = self.idms.proxy_read().await?;
440 let ident = idms_prox_read
441 .validate_client_auth_info_to_ident(client_auth_info, ct)
442 .map_err(|e| {
443 error!("Invalid identity: {:?}", e);
444 e
445 })?;
446 let srch = match SearchEvent::from_internal_message(
448 ident,
449 &filter,
450 attrs.as_deref(),
451 &mut idms_prox_read.qs_read,
452 ) {
453 Ok(s) => s,
454 Err(e) => {
455 error!("Failed to begin internal api search: {:?}", e);
456 return Err(e);
457 }
458 };
459
460 trace!(?srch, "Begin event");
461
462 match idms_prox_read.qs_read.search_ext(&srch) {
463 Ok(entries) => SearchResult::new(&mut idms_prox_read.qs_read, &entries)
464 .map(|ok_sr| ok_sr.into_proto_array()),
465 Err(e) => Err(e),
466 }
467 }
468
469 #[instrument(
470 level = "info",
471 skip_all,
472 fields(uuid = ?eventid)
473 )]
474 pub async fn handle_search_refers(
475 &self,
476 client_auth_info: ClientAuthInfo,
477 filter: Filter<FilterInvalid>,
478 uuid_or_name: String,
479 attrs: Option<Vec<String>>,
480 eventid: Uuid,
481 ) -> Result<Vec<ProtoEntry>, OperationError> {
482 let ct = duration_from_epoch_now();
483 let mut idms_prox_read = self.idms.proxy_read().await?;
484 let ident = idms_prox_read
485 .validate_client_auth_info_to_ident(client_auth_info, ct)
486 .map_err(|e| {
487 error!("Invalid identity: {:?}", e);
488 e
489 })?;
490
491 let target_uuid = idms_prox_read
492 .qs_read
493 .name_to_uuid(uuid_or_name.as_str())
494 .inspect_err(|err| {
495 error!(?err, "Error resolving id to target");
496 })?;
497
498 let filter = Filter::join_parts_and(
500 filter,
501 filter_all!(f_eq(Attribute::Refers, PartialValue::Refer(target_uuid))),
502 );
503
504 let srch = match SearchEvent::from_internal_message(
506 ident,
507 &filter,
508 attrs.as_deref(),
509 &mut idms_prox_read.qs_read,
510 ) {
511 Ok(s) => s,
512 Err(e) => {
513 error!("Failed to begin internal api search: {:?}", e);
514 return Err(e);
515 }
516 };
517
518 trace!(?srch, "Begin event");
519
520 match idms_prox_read.qs_read.search_ext(&srch) {
521 Ok(entries) => SearchResult::new(&mut idms_prox_read.qs_read, &entries)
522 .map(|ok_sr| ok_sr.into_proto_array()),
523 Err(e) => Err(e),
524 }
525 }
526
527 #[instrument(
528 level = "info",
529 skip_all,
530 fields(uuid = ?eventid)
531 )]
532 pub async fn handle_internalsearchrecycled(
533 &self,
534 client_auth_info: ClientAuthInfo,
535 filter: Filter<FilterInvalid>,
536 attrs: Option<Vec<String>>,
537 eventid: Uuid,
538 ) -> Result<Vec<ProtoEntry>, OperationError> {
539 let ct = duration_from_epoch_now();
540 let mut idms_prox_read = self.idms.proxy_read().await?;
541
542 let ident = idms_prox_read
543 .validate_client_auth_info_to_ident(client_auth_info, ct)
544 .map_err(|e| {
545 error!("Invalid identity: {:?}", e);
546 e
547 })?;
548 let srch = match SearchEvent::from_internal_recycle_message(
550 ident,
551 &filter,
552 attrs.as_deref(),
553 &idms_prox_read.qs_read,
554 ) {
555 Ok(s) => s,
556 Err(e) => {
557 error!("Failed to begin recycled search: {:?}", e);
558 return Err(e);
559 }
560 };
561
562 trace!(?srch, "Begin event");
563
564 match idms_prox_read.qs_read.search_ext(&srch) {
565 Ok(entries) => SearchResult::new(&mut idms_prox_read.qs_read, &entries)
566 .map(|ok_sr| ok_sr.into_proto_array()),
567 Err(e) => Err(e),
568 }
569 }
570
571 #[instrument(
572 level = "info",
573 skip_all,
574 fields(uuid = ?eventid)
575 )]
576 pub async fn handle_internalradiusread(
577 &self,
578 client_auth_info: ClientAuthInfo,
579 uuid_or_name: String,
580 eventid: Uuid,
581 ) -> Result<Option<String>, OperationError> {
582 let ct = duration_from_epoch_now();
583 let mut idms_prox_read = self.idms.proxy_read().await?;
584 let ident = idms_prox_read
585 .validate_client_auth_info_to_ident(client_auth_info, ct)
586 .map_err(|e| {
587 error!("Invalid identity: {:?}", e);
588 e
589 })?;
590
591 let target_uuid = idms_prox_read
592 .qs_read
593 .name_to_uuid(uuid_or_name.as_str())
594 .inspect_err(|err| {
595 error!(?err, "Error resolving id to target");
596 })?;
597
598 let srch = match SearchEvent::from_target_uuid_request(
600 ident,
601 target_uuid,
602 &idms_prox_read.qs_read,
603 ) {
604 Ok(s) => s,
605 Err(e) => {
606 error!("Failed to begin radius read: {:?}", e);
607 return Err(e);
608 }
609 };
610
611 trace!(?srch, "Begin event");
612
613 match idms_prox_read.qs_read.search_ext(&srch) {
615 Ok(mut entries) => {
616 let r = entries
617 .pop()
618 .and_then(|entry| {
620 entry
621 .get_ava_single(Attribute::RadiusSecret)
622 .and_then(|v| v.get_secret_str().map(str::to_string))
623 });
624 Ok(r)
625 }
626 Err(e) => Err(e),
627 }
628 }
629
630 #[instrument(
631 level = "info",
632 skip_all,
633 fields(uuid = ?eventid)
634 )]
635 pub async fn handle_internalradiustokenread(
636 &self,
637 client_auth_info: ClientAuthInfo,
638 uuid_or_name: String,
639 eventid: Uuid,
640 ) -> Result<RadiusAuthToken, OperationError> {
641 let ct = duration_from_epoch_now();
642 let mut idms_prox_read = self.idms.proxy_read().await?;
643
644 let ident = idms_prox_read
645 .validate_client_auth_info_to_ident(client_auth_info, ct)
646 .map_err(|e| {
647 error!("Invalid identity: {:?}", e);
648 e
649 })?;
650
651 let target_uuid = idms_prox_read
652 .qs_read
653 .name_to_uuid(uuid_or_name.as_str())
654 .inspect_err(|err| {
655 error!(?err, "Error resolving id to target");
656 })?;
657
658 let rate = match RadiusAuthTokenEvent::from_parts(
660 ident,
662 target_uuid,
663 ) {
664 Ok(s) => s,
665 Err(e) => {
666 error!("Failed to begin radius token read: {:?}", e);
667 return Err(e);
668 }
669 };
670
671 trace!(?rate, "Begin event");
672
673 idms_prox_read.get_radiusauthtoken(&rate, ct)
674 }
675
676 #[instrument(
677 level = "info",
678 skip_all,
679 fields(uuid = ?eventid)
680 )]
681 pub async fn handle_internalunixusertokenread(
682 &self,
683 client_auth_info: ClientAuthInfo,
684 uuid_or_name: String,
685 eventid: Uuid,
686 ) -> Result<UnixUserToken, OperationError> {
687 let ct = duration_from_epoch_now();
688 let mut idms_prox_read = self.idms.proxy_read().await?;
689
690 let ident = idms_prox_read
691 .validate_client_auth_info_to_ident(client_auth_info, ct)
692 .map_err(|e| {
693 error!("Invalid identity: {:?}", e);
694 e
695 })?;
696
697 let target_uuid = idms_prox_read
698 .qs_read
699 .name_to_uuid(uuid_or_name.as_str())
700 .map_err(|e| {
701 let uuid_or_name_val = match uuid_or_name.is_empty() {
704 true => "<empty uuid_or_name>",
705 false => &uuid_or_name,
706 };
707 admin_info!(
708 err = ?e,
709 "Error resolving {} as gidnumber continuing ...",
710 uuid_or_name_val
711 );
712 e
713 })?;
714
715 let rate = match UnixUserTokenEvent::from_parts(ident, target_uuid) {
717 Ok(s) => s,
718 Err(e) => {
719 error!("Failed to begin unix token read: {:?}", e);
720 return Err(e);
721 }
722 };
723
724 trace!(?rate, "Begin event");
725
726 idms_prox_read.get_unixusertoken(&rate, ct)
727 }
728
729 #[instrument(
730 level = "info",
731 skip_all,
732 fields(uuid = ?eventid)
733 )]
734 pub async fn handle_internalunixgrouptokenread(
735 &self,
736 client_auth_info: ClientAuthInfo,
737 uuid_or_name: String,
738 eventid: Uuid,
739 ) -> Result<UnixGroupToken, OperationError> {
740 let ct = duration_from_epoch_now();
741 let mut idms_prox_read = self.idms.proxy_read().await?;
742 let ident = idms_prox_read
743 .validate_client_auth_info_to_ident(client_auth_info, ct)
744 .map_err(|e| {
745 error!("Invalid identity: {:?}", e);
746 e
747 })?;
748
749 let target_uuid = idms_prox_read
750 .qs_read
751 .name_to_uuid(uuid_or_name.as_str())
752 .map_err(|e| {
753 admin_info!(err = ?e, "Error resolving as gidnumber continuing");
754 e
755 })?;
756
757 let rate = match UnixGroupTokenEvent::from_parts(
759 ident,
761 target_uuid,
762 ) {
763 Ok(s) => s,
764 Err(e) => {
765 error!("Failed to begin unix group token read: {:?}", e);
766 return Err(e);
767 }
768 };
769
770 trace!(?rate, "Begin event");
771
772 idms_prox_read.get_unixgrouptoken(&rate)
773 }
774
775 #[instrument(
776 level = "info",
777 skip_all,
778 fields(uuid = ?eventid)
779 )]
780 pub async fn handle_internalsshkeyread(
781 &self,
782 client_auth_info: ClientAuthInfo,
783 uuid_or_name: String,
784 eventid: Uuid,
785 ) -> Result<Vec<String>, OperationError> {
786 let ct = duration_from_epoch_now();
787 let mut idms_prox_read = self.idms.proxy_read().await?;
788 let ident = idms_prox_read
789 .validate_client_auth_info_to_ident(client_auth_info, ct)
790 .map_err(|e| {
791 error!("Invalid identity: {:?}", e);
792 e
793 })?;
794 let target_uuid = idms_prox_read
795 .qs_read
796 .name_to_uuid(uuid_or_name.as_str())
797 .inspect_err(|err| {
798 error!(?err, "Error resolving id to target");
799 })?;
800
801 let srch = match SearchEvent::from_target_uuid_request(
803 ident,
804 target_uuid,
805 &idms_prox_read.qs_read,
806 ) {
807 Ok(s) => s,
808 Err(e) => {
809 error!("Failed to begin ssh key read: {:?}", e);
810 return Err(e);
811 }
812 };
813
814 trace!(?srch, "Begin event");
815
816 match idms_prox_read.qs_read.search_ext(&srch) {
817 Ok(mut entries) => {
818 let r = entries
819 .pop()
820 .and_then(|e| {
822 e.get_ava_iter_sshpubkeys(Attribute::SshPublicKey)
824 .map(|i| i.collect())
825 })
826 .unwrap_or_else(|| {
827 Vec::new()
829 });
830 Ok(r)
831 }
832 Err(e) => Err(e),
833 }
834 }
835
836 #[instrument(
837 level = "info",
838 skip_all,
839 fields(uuid = ?eventid)
840 )]
841 pub async fn handle_internalsshkeytagread(
842 &self,
843 client_auth_info: ClientAuthInfo,
844 uuid_or_name: String,
845 tag: String,
846 eventid: Uuid,
847 ) -> Result<Option<String>, OperationError> {
848 let ct = duration_from_epoch_now();
849 let mut idms_prox_read = self.idms.proxy_read().await?;
850 let ident = idms_prox_read
851 .validate_client_auth_info_to_ident(client_auth_info, ct)
852 .map_err(|e| {
853 error!("Invalid identity: {:?}", e);
854 e
855 })?;
856 let target_uuid = idms_prox_read
857 .qs_read
858 .name_to_uuid(uuid_or_name.as_str())
859 .inspect_err(|err| {
860 admin_info!(?err, "Error resolving id to target");
861 })?;
862
863 let srch = match SearchEvent::from_target_uuid_request(
865 ident,
866 target_uuid,
867 &idms_prox_read.qs_read,
868 ) {
869 Ok(s) => s,
870 Err(e) => {
871 error!("Failed to begin sshkey tag read: {:?}", e);
872 return Err(e);
873 }
874 };
875
876 trace!(?srch, "Begin event");
877
878 match idms_prox_read.qs_read.search_ext(&srch) {
879 Ok(mut entries) => {
880 let r = entries
881 .pop()
882 .map(|e| {
884 e.get_ava_set(Attribute::SshPublicKey).and_then(|vs| {
886 vs.get_ssh_tag(&tag).map(|pk| pk.to_string())
888 })
889 })
890 .unwrap_or_else(|| {
891 None
893 });
894 Ok(r)
895 }
896 Err(e) => Err(e),
897 }
898 }
899
900 #[instrument(
901 level = "info",
902 skip_all,
903 fields(uuid = ?eventid)
904 )]
905 pub async fn handle_service_account_api_token_get(
906 &self,
907 client_auth_info: ClientAuthInfo,
908 uuid_or_name: String,
909 eventid: Uuid,
910 ) -> Result<Vec<ApiToken>, OperationError> {
911 let ct = duration_from_epoch_now();
912 let mut idms_prox_read = self.idms.proxy_read().await?;
913 let ident = idms_prox_read
914 .validate_client_auth_info_to_ident(client_auth_info, ct)
915 .map_err(|e| {
916 error!("Invalid identity: {:?}", e);
917 e
918 })?;
919 let target = idms_prox_read
920 .qs_read
921 .name_to_uuid(uuid_or_name.as_str())
922 .inspect_err(|err| {
923 error!(?err, "Error resolving id to target");
924 })?;
925
926 let lte = ListApiTokenEvent { ident, target };
927
928 idms_prox_read.service_account_list_api_token(<e)
929 }
930
931 #[instrument(
932 level = "info",
933 skip_all,
934 fields(uuid = ?eventid)
935 )]
936 pub async fn handle_account_user_auth_token_get(
937 &self,
938 client_auth_info: ClientAuthInfo,
939 uuid_or_name: String,
940 eventid: Uuid,
941 ) -> Result<Vec<UatStatus>, OperationError> {
942 let ct = duration_from_epoch_now();
943 let mut idms_prox_read = self.idms.proxy_read().await?;
944 let ident = idms_prox_read
945 .validate_client_auth_info_to_ident(client_auth_info, ct)
946 .map_err(|e| {
947 error!("Invalid identity: {:?}", e);
948 e
949 })?;
950 let target = idms_prox_read
951 .qs_read
952 .name_to_uuid(uuid_or_name.as_str())
953 .inspect_err(|err| {
954 error!(?err, "Error resolving id to target");
955 })?;
956
957 let lte = ListUserAuthTokenEvent { ident, target };
958
959 idms_prox_read.account_list_user_auth_tokens(<e)
960 }
961
962 #[instrument(
963 level = "info",
964 skip_all,
965 fields(uuid = ?eventid)
966 )]
967 pub async fn handle_user_identity_verification(
968 &self,
969 client_auth_info: ClientAuthInfo,
970 eventid: Uuid,
971 user_request: IdentifyUserRequest,
972 other_id: String,
973 ) -> Result<IdentifyUserResponse, OperationError> {
974 trace!("{:?}", &user_request);
975 let ct = duration_from_epoch_now();
976 let mut idms_prox_read = self.idms.proxy_read().await?;
977 let ident = idms_prox_read
978 .validate_client_auth_info_to_ident(client_auth_info, ct)
979 .map_err(|e| {
980 error!("Invalid identity: {:?}", e);
981 e
982 })?;
983 let target = idms_prox_read
984 .qs_read
985 .name_to_uuid(&other_id)
986 .map_err(|e| {
987 error!("No user found with the provided ID: {:?}", e);
988 e
989 })?;
990 match user_request {
991 IdentifyUserRequest::Start => idms_prox_read
992 .handle_identify_user_start(&IdentifyUserStartEvent::new(target, ident)),
993 IdentifyUserRequest::DisplayCode => idms_prox_read.handle_identify_user_display_code(
994 &IdentifyUserDisplayCodeEvent::new(target, ident),
995 ),
996 IdentifyUserRequest::SubmitCode { other_totp } => idms_prox_read
997 .handle_identify_user_submit_code(&IdentifyUserSubmitCodeEvent::new(
998 target, ident, other_totp,
999 )),
1000 }
1001 }
1002
1003 #[instrument(
1004 level = "info",
1005 skip_all,
1006 fields(uuid = ?eventid)
1007 )]
1008 pub async fn handle_idmaccountunixauth(
1009 &self,
1010 client_auth_info: ClientAuthInfo,
1011 uuid_or_name: String,
1012 cred: String,
1013 eventid: Uuid,
1014 ) -> Result<Option<UnixUserToken>, OperationError> {
1015 let ct = duration_from_epoch_now();
1016 let mut idm_auth = self.idms.auth().await?;
1017 let ident = idm_auth
1019 .validate_client_auth_info_to_ident(client_auth_info, ct)
1020 .map_err(|e| {
1021 error!(err = ?e, "Invalid identity");
1022 e
1023 })?;
1024
1025 let target_uuid = idm_auth
1026 .qs_read
1027 .name_to_uuid(uuid_or_name.as_str())
1028 .map_err(|e| {
1029 admin_info!(err = ?e, "Error resolving as gidnumber continuing");
1030 e
1031 })?;
1032 let uuae = match UnixUserAuthEvent::from_parts(ident, target_uuid, cred) {
1034 Ok(s) => s,
1035 Err(e) => {
1036 error!(err = ?e, "Failed to begin unix auth");
1037 return Err(e);
1038 }
1039 };
1040
1041 security_info!(event = ?uuae, "Begin unix auth event");
1042
1043 let res = idm_auth
1044 .auth_unix(&uuae, ct)
1045 .await
1046 .and_then(|r| idm_auth.commit().map(|_| r));
1047
1048 security_info!(?res, "Sending result");
1049
1050 res
1051 }
1052
1053 #[instrument(
1054 level = "info",
1055 skip_all,
1056 fields(uuid = ?eventid)
1057 )]
1058 pub async fn handle_idmcredentialstatus(
1059 &self,
1060 client_auth_info: ClientAuthInfo,
1061 uuid_or_name: String,
1062 eventid: Uuid,
1063 ) -> Result<CredentialStatus, OperationError> {
1064 let ct = duration_from_epoch_now();
1065 let mut idms_prox_read = self.idms.proxy_read().await?;
1066
1067 let ident = idms_prox_read
1068 .validate_client_auth_info_to_ident(client_auth_info, ct)
1069 .map_err(|e| {
1070 error!(err = ?e, "Invalid identity");
1071 e
1072 })?;
1073 let target_uuid = idms_prox_read
1074 .qs_read
1075 .name_to_uuid(uuid_or_name.as_str())
1076 .map_err(|e| {
1077 error!(err = ?e, "Error resolving id to target");
1078 e
1079 })?;
1080
1081 let cse = match CredentialStatusEvent::from_parts(
1083 ident,
1085 target_uuid,
1086 ) {
1087 Ok(s) => s,
1088 Err(e) => {
1089 error!(err = ?e, "Failed to begin credential status read");
1090 return Err(e);
1091 }
1092 };
1093
1094 trace!(?cse, "Begin event");
1095
1096 idms_prox_read.get_credentialstatus(&cse)
1097 }
1098
1099 #[instrument(
1100 level = "info",
1101 skip_all,
1102 fields(uuid = ?eventid)
1103 )]
1104 pub async fn handle_idmbackupcodeview(
1105 &self,
1106 client_auth_info: ClientAuthInfo,
1107 uuid_or_name: String,
1108 eventid: Uuid,
1109 ) -> Result<BackupCodesView, OperationError> {
1110 let ct = duration_from_epoch_now();
1111 let mut idms_prox_read = self.idms.proxy_read().await?;
1112
1113 let ident = idms_prox_read
1114 .validate_client_auth_info_to_ident(client_auth_info, ct)
1115 .map_err(|e| {
1116 error!("Invalid identity: {:?}", e);
1117 e
1118 })?;
1119 let target_uuid = idms_prox_read
1120 .qs_read
1121 .name_to_uuid(uuid_or_name.as_str())
1122 .inspect_err(|err| {
1123 error!(?err, "Error resolving id to target");
1124 })?;
1125
1126 let rbce = match ReadBackupCodeEvent::from_parts(
1128 ident,
1130 target_uuid,
1131 ) {
1132 Ok(s) => s,
1133 Err(e) => {
1134 error!("Failed to begin backup code read: {:?}", e);
1135 return Err(e);
1136 }
1137 };
1138
1139 trace!(?rbce, "Begin event");
1140
1141 idms_prox_read.get_backup_codes(&rbce)
1142 }
1143
1144 #[instrument(
1145 level = "info",
1146 skip_all,
1147 fields(uuid = ?eventid)
1148 )]
1149 pub async fn handle_idmcredentialupdatestatus(
1150 &self,
1151 session_token: CUSessionToken,
1152 eventid: Uuid,
1153 ) -> Result<CUStatus, OperationError> {
1154 let session_token = JweCompact::from_str(&session_token.token)
1155 .map(|token_enc| CredentialUpdateSessionToken { token_enc })
1156 .map_err(|err| {
1157 error!(?err, "malformed token");
1158 OperationError::InvalidRequestState
1159 })?;
1160
1161 let ct = duration_from_epoch_now();
1163 let idms_cred_update = self.idms.cred_update_transaction().await?;
1164
1165 idms_cred_update
1166 .credential_update_status(&session_token, ct)
1167 .map_err(|e| {
1168 error!(
1169 err = ?e,
1170 "Failed to begin credential_update_status",
1171 );
1172 e
1173 })
1174 .map(|sta| sta.into())
1175 }
1176
1177 #[instrument(
1178 level = "info",
1179 skip_all,
1180 fields(uuid = ?eventid)
1181 )]
1182 pub async fn handle_idmcredentialupdate(
1183 &self,
1184 session_token: CUSessionToken,
1185 scr: CURequest,
1186 eventid: Uuid,
1187 ) -> Result<CUStatus, OperationError> {
1188 let session_token = JweCompact::from_str(&session_token.token)
1189 .map(|token_enc| CredentialUpdateSessionToken { token_enc })
1190 .map_err(|err| {
1191 error!(?err, "Invalid Token - Must be a compact JWE");
1192 OperationError::InvalidRequestState
1193 })?;
1194
1195 let ct = duration_from_epoch_now();
1196 let idms_cred_update = self.idms.cred_update_transaction().await?;
1197
1198 debug!(?scr);
1199
1200 match scr {
1201 CURequest::PrimaryRemove => idms_cred_update
1202 .credential_primary_delete(&session_token, ct)
1203 .map_err(|e| {
1204 error!(
1205 err = ?e,
1206 "Failed to begin credential_primary_delete",
1207 );
1208 e
1209 }),
1210 CURequest::Password(pw) => idms_cred_update
1211 .credential_primary_set_password(&session_token, ct, &pw)
1212 .map_err(|e| {
1213 error!(
1214 err = ?e,
1215 "Failed to begin credential_primary_set_password",
1216 );
1217 e
1218 }),
1219 CURequest::CancelMFAReg => idms_cred_update
1220 .credential_update_cancel_mfareg(&session_token, ct)
1221 .map_err(|e| {
1222 error!(
1223 err = ?e,
1224 "Failed to begin credential_update_cancel_mfareg",
1225 );
1226 e
1227 }),
1228 CURequest::TotpGenerate => idms_cred_update
1229 .credential_primary_init_totp(&session_token, ct)
1230 .map_err(|e| {
1231 error!(
1232 err = ?e,
1233 "Failed to begin credential_primary_init_totp",
1234 );
1235 e
1236 }),
1237 CURequest::TotpVerify(totp_chal, label) => idms_cred_update
1238 .credential_primary_check_totp(&session_token, ct, totp_chal, &label)
1239 .map_err(|e| {
1240 error!(
1241 err = ?e,
1242 "Failed to begin credential_primary_check_totp",
1243 );
1244 e
1245 }),
1246 CURequest::TotpAcceptSha1 => idms_cred_update
1247 .credential_primary_accept_sha1_totp(&session_token, ct)
1248 .map_err(|e| {
1249 error!(
1250 err = ?e,
1251 "Failed to begin credential_primary_accept_sha1_totp",
1252 );
1253 e
1254 }),
1255 CURequest::TotpRemove(label) => idms_cred_update
1256 .credential_primary_remove_totp(&session_token, ct, &label)
1257 .map_err(|e| {
1258 error!(
1259 err = ?e,
1260 "Failed to begin credential_primary_remove_totp",
1261 );
1262 e
1263 }),
1264 CURequest::BackupCodeGenerate => idms_cred_update
1265 .credential_primary_init_backup_codes(&session_token, ct)
1266 .map_err(|e| {
1267 error!(
1268 err = ?e,
1269 "Failed to begin credential_primary_init_backup_codes",
1270 );
1271 e
1272 }),
1273 CURequest::BackupCodeRemove => idms_cred_update
1274 .credential_primary_remove_backup_codes(&session_token, ct)
1275 .map_err(|e| {
1276 error!(
1277 err = ?e,
1278 "Failed to begin credential_primary_remove_backup_codes",
1279 );
1280 e
1281 }),
1282 CURequest::PasskeyInit => idms_cred_update
1283 .credential_passkey_init(&session_token, ct)
1284 .map_err(|e| {
1285 error!(
1286 err = ?e,
1287 "Failed to begin credential_passkey_init",
1288 );
1289 e
1290 }),
1291 CURequest::PasskeyFinish(label, rpkc) => idms_cred_update
1292 .credential_passkey_finish(&session_token, ct, label, &rpkc)
1293 .map_err(|e| {
1294 error!(
1295 err = ?e,
1296 "Failed to begin credential_passkey_finish",
1297 );
1298 e
1299 }),
1300 CURequest::PasskeyRemove(uuid) => idms_cred_update
1301 .credential_passkey_remove(&session_token, ct, uuid)
1302 .map_err(|e| {
1303 error!(
1304 err = ?e,
1305 "Failed to begin credential_passkey_remove"
1306 );
1307 e
1308 }),
1309 CURequest::AttestedPasskeyInit => idms_cred_update
1310 .credential_attested_passkey_init(&session_token, ct)
1311 .map_err(|e| {
1312 error!(
1313 err = ?e,
1314 "Failed to begin credential_attested_passkey_init"
1315 );
1316 e
1317 }),
1318 CURequest::AttestedPasskeyFinish(label, rpkc) => idms_cred_update
1319 .credential_attested_passkey_finish(&session_token, ct, label, &rpkc)
1320 .map_err(|e| {
1321 error!(
1322 err = ?e,
1323 "Failed to begin credential_attested_passkey_finish"
1324 );
1325 e
1326 }),
1327 CURequest::AttestedPasskeyRemove(uuid) => idms_cred_update
1328 .credential_attested_passkey_remove(&session_token, ct, uuid)
1329 .map_err(|e| {
1330 error!(
1331 err = ?e,
1332 "Failed to begin credential_attested_passkey_remove"
1333 );
1334 e
1335 }),
1336 CURequest::UnixPasswordRemove => idms_cred_update
1337 .credential_unix_delete(&session_token, ct)
1338 .inspect_err(|err| {
1339 error!(?err, "Failed to begin credential_unix_delete");
1340 }),
1341 CURequest::UnixPassword(pw) => idms_cred_update
1342 .credential_unix_set_password(&session_token, ct, &pw)
1343 .inspect_err(|err| {
1344 error!(?err, "Failed to begin credential_unix_set_password");
1345 }),
1346
1347 CURequest::SshPublicKey(label, pubkey) => idms_cred_update
1348 .credential_sshkey_add(&session_token, ct, label, pubkey)
1349 .inspect_err(|err| {
1350 error!(?err, "Failed to begin credential_sshkey_remove");
1351 }),
1352
1353 CURequest::SshPublicKeyRemove(label) => idms_cred_update
1354 .credential_sshkey_remove(&session_token, ct, &label)
1355 .inspect_err(|err| {
1356 error!(?err, "Failed to begin credential_sshkey_remove");
1357 }),
1358 }
1359 .map(|sta| sta.into())
1360 }
1361
1362 #[instrument(
1363 level = "info",
1364 skip_all,
1365 fields(uuid = ?eventid)
1366 )]
1367 pub async fn handle_oauth2_basic_secret_read(
1368 &self,
1369 client_auth_info: ClientAuthInfo,
1370 filter: Filter<FilterInvalid>,
1371 eventid: Uuid,
1372 ) -> Result<Option<String>, OperationError> {
1373 let ct = duration_from_epoch_now();
1374 let mut idms_prox_read = self.idms.proxy_read().await?;
1375 let ident = idms_prox_read
1376 .validate_client_auth_info_to_ident(client_auth_info, ct)
1377 .map_err(|e| {
1378 error!("Invalid identity: {:?}", e);
1379 e
1380 })?;
1381
1382 let srch = match SearchEvent::from_internal_message(
1384 ident,
1385 &filter,
1386 None,
1387 &mut idms_prox_read.qs_read,
1388 ) {
1389 Ok(s) => s,
1390 Err(e) => {
1391 error!("Failed to begin oauth2 basic secret read: {:?}", e);
1392 return Err(e);
1393 }
1394 };
1395
1396 trace!(?srch, "Begin event");
1397
1398 match idms_prox_read.qs_read.search_ext(&srch) {
1400 Ok(mut entries) => {
1401 let r = entries
1402 .pop()
1403 .and_then(|entry| {
1405 entry
1406 .get_ava_single(Attribute::OAuth2RsBasicSecret)
1407 .and_then(|v| v.get_secret_str().map(str::to_string))
1408 });
1409 Ok(r)
1410 }
1411 Err(e) => Err(e),
1412 }
1413 }
1414
1415 #[instrument(
1416 level = "info",
1417 skip_all,
1418 fields(uuid = ?eventid)
1419 )]
1420 pub async fn handle_oauth2_authorise(
1421 &self,
1422 client_auth_info: ClientAuthInfo,
1423 auth_req: AuthorisationRequest,
1424 eventid: Uuid,
1425 ) -> Result<AuthoriseResponse, Oauth2Error> {
1426 let ct = duration_from_epoch_now();
1427 let mut idms_prox_read = self
1428 .idms
1429 .proxy_read()
1430 .await
1431 .map_err(Oauth2Error::ServerError)?;
1432 let ident = idms_prox_read
1433 .validate_client_auth_info_to_ident(client_auth_info, ct)
1434 .inspect_err(|e| {
1435 error!("Invalid identity: {:?}", e);
1436 })
1437 .ok();
1438
1439 idms_prox_read.check_oauth2_authorisation(ident.as_ref(), &auth_req, ct)
1441 }
1442
1443 #[instrument(
1444 level = "info",
1445 skip_all,
1446 fields(uuid = ?eventid)
1447 )]
1448 pub async fn handle_oauth2_authorise_reject(
1449 &self,
1450 client_auth_info: ClientAuthInfo,
1451 consent_req: String,
1452 eventid: Uuid,
1453 ) -> Result<AuthoriseReject, OperationError> {
1454 let ct = duration_from_epoch_now();
1455 let mut idms_prox_read = self.idms.proxy_read().await?;
1456 let ident = idms_prox_read
1457 .validate_client_auth_info_to_ident(client_auth_info, ct)
1458 .map_err(|e| {
1459 error!("Invalid identity: {:?}", e);
1460 e
1461 })?;
1462
1463 idms_prox_read.check_oauth2_authorise_reject(&ident, &consent_req, ct)
1464 }
1465
1466 #[instrument(
1467 level = "info",
1468 skip_all,
1469 fields(uuid = ?eventid)
1470 )]
1471 pub async fn handle_oauth2_token_introspect(
1472 &self,
1473 client_auth_info: ClientAuthInfo,
1474 intr_req: AccessTokenIntrospectRequest,
1475 eventid: Uuid,
1476 ) -> Result<AccessTokenIntrospectResponse, Oauth2Error> {
1477 let ct = duration_from_epoch_now();
1478 let mut idms_prox_read = self
1479 .idms
1480 .proxy_read()
1481 .await
1482 .map_err(Oauth2Error::ServerError)?;
1483 idms_prox_read.check_oauth2_token_introspect(&client_auth_info, &intr_req, ct)
1485 }
1486
1487 #[instrument(
1488 level = "info",
1489 skip_all,
1490 fields(uuid = ?eventid)
1491 )]
1492 pub async fn handle_oauth2_openid_userinfo(
1493 &self,
1494 client_id: String,
1495 token: JwsCompact,
1496 eventid: Uuid,
1497 ) -> Result<OidcToken, Oauth2Error> {
1498 let ct = duration_from_epoch_now();
1499 let mut idms_prox_read = self
1500 .idms
1501 .proxy_read()
1502 .await
1503 .map_err(Oauth2Error::ServerError)?;
1504 idms_prox_read.oauth2_openid_userinfo(&client_id, token, ct)
1505 }
1506
1507 #[instrument(
1508 level = "info",
1509 skip_all,
1510 fields(uuid = ?eventid)
1511 )]
1512 pub async fn handle_oauth2_openid_discovery(
1513 &self,
1514 client_id: String,
1515 eventid: Uuid,
1516 ) -> Result<OidcDiscoveryResponse, OperationError> {
1517 let idms_prox_read = self.idms.proxy_read().await?;
1518 idms_prox_read.oauth2_openid_discovery(&client_id)
1519 }
1520
1521 #[instrument(
1522 level = "info",
1523 skip_all,
1524 fields(uuid = ?eventid)
1525 )]
1526 pub async fn handle_oauth2_webfinger_discovery(
1527 &self,
1528 client_id: &str,
1529 resource_id: &str,
1530 eventid: Uuid,
1531 ) -> Result<OidcWebfingerResponse, OperationError> {
1532 let mut idms_prox_read = self.idms.proxy_read().await?;
1533 idms_prox_read.oauth2_openid_webfinger(client_id, resource_id)
1534 }
1535
1536 #[instrument(
1537 level = "info",
1538 skip_all,
1539 fields(uuid = ?eventid)
1540 )]
1541 pub async fn handle_oauth2_rfc8414_metadata(
1542 &self,
1543 client_id: String,
1544 eventid: Uuid,
1545 ) -> Result<Oauth2Rfc8414MetadataResponse, OperationError> {
1546 let idms_prox_read = self.idms.proxy_read().await?;
1547 idms_prox_read.oauth2_rfc8414_metadata(&client_id)
1548 }
1549
1550 #[instrument(
1551 level = "info",
1552 skip_all,
1553 fields(uuid = ?eventid)
1554 )]
1555 pub async fn handle_oauth2_openid_publickey(
1556 &self,
1557 client_id: String,
1558 eventid: Uuid,
1559 ) -> Result<JwkKeySet, OperationError> {
1560 let idms_prox_read = self.idms.proxy_read().await?;
1561 idms_prox_read.oauth2_openid_publickey(&client_id)
1562 }
1563
1564 #[instrument(
1565 level = "info",
1566 skip_all,
1567 fields(uuid = ?eventid)
1568 )]
1569 pub async fn handle_list_applinks(
1570 &self,
1571 client_auth_info: ClientAuthInfo,
1572 eventid: Uuid,
1573 ) -> Result<Vec<AppLink>, OperationError> {
1574 let ct = duration_from_epoch_now();
1575 let mut idms_prox_read = self.idms.proxy_read().await?;
1576 let ident = idms_prox_read
1577 .validate_client_auth_info_to_ident(client_auth_info, ct)
1578 .map_err(|e| {
1579 error!("Invalid identity: {:?}", e);
1580 e
1581 })?;
1582
1583 idms_prox_read.list_applinks(&ident)
1585 }
1586
1587 #[instrument(
1588 level = "info",
1589 skip_all,
1590 fields(uuid = ?eventid)
1591 )]
1592 pub async fn handle_auth_valid(
1593 &self,
1594 client_auth_info: ClientAuthInfo,
1595 eventid: Uuid,
1596 ) -> Result<(), OperationError> {
1597 let ct = duration_from_epoch_now();
1598 let mut idms_prox_read = self.idms.proxy_read().await?;
1599
1600 idms_prox_read
1601 .validate_client_auth_info_to_ident(client_auth_info, ct)
1602 .map(|_| ())
1603 .map_err(|e| {
1604 error!("Invalid identity: {:?}", e);
1605 e
1606 })
1607 }
1608
1609 #[instrument(
1610 level = "info",
1611 skip_all,
1612 fields(uuid = ?eventid)
1613 )]
1614 pub async fn handle_public_jwk_get(
1616 &self,
1617 key_id: String,
1618 eventid: Uuid,
1619 ) -> Result<Jwk, OperationError> {
1620 let mut idms_prox_read = self.idms.proxy_read().await?;
1621
1622 idms_prox_read.jws_public_jwk(key_id.as_str())
1623 }
1624
1625 #[instrument(
1626 level = "info",
1627 skip_all,
1628 fields(uuid = ?eventid)
1629 )]
1630 pub async fn handle_ldaprequest(
1631 &self,
1632 eventid: Uuid,
1633 protomsg: LdapMsg,
1634 uat: Option<LdapBoundToken>,
1635 ip_addr: IpAddr,
1636 ) -> Option<LdapResponseState> {
1637 let res = match ServerOps::try_from(protomsg) {
1638 Ok(server_op) => self
1639 .ldap
1640 .do_op(&self.idms, server_op, uat, ip_addr, eventid)
1641 .await
1642 .unwrap_or_else(|e| {
1643 error!("do_op failed -> {:?}", e);
1644 LdapResponseState::Disconnect(DisconnectionNotice::gen(
1645 LdapResultCode::Other,
1646 format!("Internal Server Error {:?}", &eventid).as_str(),
1647 ))
1648 }),
1649 Err(_) => LdapResponseState::Disconnect(DisconnectionNotice::gen(
1650 LdapResultCode::ProtocolError,
1651 format!("Invalid Request {:?}", &eventid).as_str(),
1652 )),
1653 };
1654 Some(res)
1655 }
1656
1657 pub fn domain_info_read(&self) -> DomainInfoRead {
1658 self.idms.domain_read()
1659 }
1660}