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