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, CURequest, CUSessionToken, CUStatus, CredentialStatus, IdentifyUserRequest,
9 IdentifyUserResponse, ImageValue, OperationError, RadiusAuthToken, SearchRequest,
10 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, UnixGroupTokenEvent,
36 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-{timestamp}.json"));
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 pub async fn pre_validate_client_auth_info(
368 &self,
369 client_auth_info: &mut ClientAuthInfo,
370 ) -> Result<(), OperationError> {
371 let ct = duration_from_epoch_now();
372 let mut idms_prox_read = self.idms.proxy_read().await?;
373 idms_prox_read
374 .pre_validate_client_auth_info(client_auth_info, ct)
375 .map_err(|e| {
376 error!(?e, "Invalid identity");
377 e
378 })
379 }
380
381 #[instrument(
382 level = "info",
383 name = "whoami_uat",
384 skip_all,
385 fields(uuid = ?eventid)
386 )]
387 pub async fn handle_whoami_uat(
388 &self,
389 client_auth_info: &ClientAuthInfo,
390 eventid: Uuid,
391 ) -> Result<UserAuthToken, OperationError> {
392 let ct = duration_from_epoch_now();
393 let mut idms_prox_read = self.idms.proxy_read().await?;
394 idms_prox_read
402 .validate_client_auth_info_to_uat(client_auth_info, ct)
403 .map_err(|e| {
404 error!(?e, "Invalid identity");
405 e
406 })
407 }
408
409 #[instrument(level = "debug", skip_all)]
410 pub async fn handle_oauth2_rs_image_get_image(
412 &self,
413 client_auth_info: ClientAuthInfo,
414 rs: Filter<FilterInvalid>,
415 ) -> Result<Option<ImageValue>, OperationError> {
416 let mut idms_prox_read = self.idms.proxy_read().await?;
417 let ct = duration_from_epoch_now();
418
419 let ident = idms_prox_read
420 .validate_client_auth_info_to_ident(client_auth_info, ct)
421 .map_err(|e| {
422 error!(err = ?e, "Invalid identity in handle_oauth2_rs_image_get_image");
423 e
424 })?;
425 let attrs = vec![Attribute::Image.to_string()];
426
427 let search = SearchEvent::from_internal_message(
428 ident,
429 &rs,
430 Some(attrs.as_slice()),
431 &mut idms_prox_read.qs_read,
432 )?;
433
434 let entries = idms_prox_read.qs_read.search(&search)?;
435 Ok(entries
436 .first()
437 .and_then(|entry| entry.get_ava_single_image(Attribute::Image)))
438 }
439
440 #[instrument(
441 level = "info",
442 skip_all,
443 fields(uuid = ?eventid)
444 )]
445 pub async fn handle_internalsearch(
446 &self,
447 client_auth_info: ClientAuthInfo,
448 filter: Filter<FilterInvalid>,
449 attrs: Option<Vec<String>>,
450 eventid: Uuid,
451 ) -> Result<Vec<ProtoEntry>, OperationError> {
452 let ct = duration_from_epoch_now();
453 let mut idms_prox_read = self.idms.proxy_read().await?;
454 let ident = idms_prox_read
455 .validate_client_auth_info_to_ident(client_auth_info, ct)
456 .map_err(|e| {
457 error!("Invalid identity: {:?}", e);
458 e
459 })?;
460 let srch = match SearchEvent::from_internal_message(
462 ident,
463 &filter,
464 attrs.as_deref(),
465 &mut idms_prox_read.qs_read,
466 ) {
467 Ok(s) => s,
468 Err(e) => {
469 error!("Failed to begin internal api search: {:?}", e);
470 return Err(e);
471 }
472 };
473
474 trace!(?srch, "Begin event");
475
476 match idms_prox_read.qs_read.search_ext(&srch) {
477 Ok(entries) => SearchResult::new(&mut idms_prox_read.qs_read, &entries)
478 .map(|ok_sr| ok_sr.into_proto_array()),
479 Err(e) => Err(e),
480 }
481 }
482
483 #[instrument(
484 level = "info",
485 skip_all,
486 fields(uuid = ?eventid)
487 )]
488 pub async fn handle_search_refers(
489 &self,
490 client_auth_info: ClientAuthInfo,
491 filter: Filter<FilterInvalid>,
492 uuid_or_name: String,
493 attrs: Option<Vec<String>>,
494 eventid: Uuid,
495 ) -> Result<Vec<ProtoEntry>, OperationError> {
496 let ct = duration_from_epoch_now();
497 let mut idms_prox_read = self.idms.proxy_read().await?;
498 let ident = idms_prox_read
499 .validate_client_auth_info_to_ident(client_auth_info, ct)
500 .map_err(|e| {
501 error!("Invalid identity: {:?}", e);
502 e
503 })?;
504
505 let target_uuid = idms_prox_read
506 .qs_read
507 .name_to_uuid(uuid_or_name.as_str())
508 .inspect_err(|err| {
509 error!(?err, "Error resolving id to target");
510 })?;
511
512 let filter = Filter::join_parts_and(
514 filter,
515 filter_all!(f_eq(Attribute::Refers, PartialValue::Refer(target_uuid))),
516 );
517
518 let srch = match SearchEvent::from_internal_message(
520 ident,
521 &filter,
522 attrs.as_deref(),
523 &mut idms_prox_read.qs_read,
524 ) {
525 Ok(s) => s,
526 Err(e) => {
527 error!("Failed to begin internal api search: {:?}", e);
528 return Err(e);
529 }
530 };
531
532 trace!(?srch, "Begin event");
533
534 match idms_prox_read.qs_read.search_ext(&srch) {
535 Ok(entries) => SearchResult::new(&mut idms_prox_read.qs_read, &entries)
536 .map(|ok_sr| ok_sr.into_proto_array()),
537 Err(e) => Err(e),
538 }
539 }
540
541 #[instrument(
542 level = "info",
543 skip_all,
544 fields(uuid = ?eventid)
545 )]
546 pub async fn handle_internalsearchrecycled(
547 &self,
548 client_auth_info: ClientAuthInfo,
549 filter: Filter<FilterInvalid>,
550 attrs: Option<Vec<String>>,
551 eventid: Uuid,
552 ) -> Result<Vec<ProtoEntry>, OperationError> {
553 let ct = duration_from_epoch_now();
554 let mut idms_prox_read = self.idms.proxy_read().await?;
555
556 let ident = idms_prox_read
557 .validate_client_auth_info_to_ident(client_auth_info, ct)
558 .map_err(|e| {
559 error!("Invalid identity: {:?}", e);
560 e
561 })?;
562 let srch = match SearchEvent::from_internal_recycle_message(
564 ident,
565 &filter,
566 attrs.as_deref(),
567 &idms_prox_read.qs_read,
568 ) {
569 Ok(s) => s,
570 Err(e) => {
571 error!("Failed to begin recycled search: {:?}", e);
572 return Err(e);
573 }
574 };
575
576 trace!(?srch, "Begin event");
577
578 match idms_prox_read.qs_read.search_ext(&srch) {
579 Ok(entries) => SearchResult::new(&mut idms_prox_read.qs_read, &entries)
580 .map(|ok_sr| ok_sr.into_proto_array()),
581 Err(e) => Err(e),
582 }
583 }
584
585 #[instrument(
586 level = "info",
587 skip_all,
588 fields(uuid = ?eventid)
589 )]
590 pub async fn handle_internalradiusread(
591 &self,
592 client_auth_info: ClientAuthInfo,
593 uuid_or_name: String,
594 eventid: Uuid,
595 ) -> Result<Option<String>, OperationError> {
596 let ct = duration_from_epoch_now();
597 let mut idms_prox_read = self.idms.proxy_read().await?;
598 let ident = idms_prox_read
599 .validate_client_auth_info_to_ident(client_auth_info, ct)
600 .map_err(|e| {
601 error!("Invalid identity: {:?}", e);
602 e
603 })?;
604
605 let target_uuid = idms_prox_read
606 .qs_read
607 .name_to_uuid(uuid_or_name.as_str())
608 .inspect_err(|err| {
609 error!(?err, "Error resolving id to target");
610 })?;
611
612 let srch = match SearchEvent::from_target_uuid_request(
614 ident,
615 target_uuid,
616 &idms_prox_read.qs_read,
617 ) {
618 Ok(s) => s,
619 Err(e) => {
620 error!("Failed to begin radius read: {:?}", e);
621 return Err(e);
622 }
623 };
624
625 trace!(?srch, "Begin event");
626
627 match idms_prox_read.qs_read.search_ext(&srch) {
629 Ok(mut entries) => {
630 let r = entries
631 .pop()
632 .and_then(|entry| {
634 entry
635 .get_ava_single(Attribute::RadiusSecret)
636 .and_then(|v| v.get_secret_str().map(str::to_string))
637 });
638 Ok(r)
639 }
640 Err(e) => Err(e),
641 }
642 }
643
644 #[instrument(
645 level = "info",
646 skip_all,
647 fields(uuid = ?eventid)
648 )]
649 pub async fn handle_internalradiustokenread(
650 &self,
651 client_auth_info: ClientAuthInfo,
652 uuid_or_name: String,
653 eventid: Uuid,
654 ) -> Result<RadiusAuthToken, OperationError> {
655 let ct = duration_from_epoch_now();
656 let mut idms_prox_read = self.idms.proxy_read().await?;
657
658 let ident = idms_prox_read
659 .validate_client_auth_info_to_ident(client_auth_info, ct)
660 .map_err(|e| {
661 error!("Invalid identity: {:?}", e);
662 e
663 })?;
664
665 let target_uuid = idms_prox_read
666 .qs_read
667 .name_to_uuid(uuid_or_name.as_str())
668 .inspect_err(|err| {
669 error!(?err, "Error resolving id to target");
670 })?;
671
672 let rate = match RadiusAuthTokenEvent::from_parts(
674 ident,
676 target_uuid,
677 ) {
678 Ok(s) => s,
679 Err(e) => {
680 error!("Failed to begin radius token read: {:?}", e);
681 return Err(e);
682 }
683 };
684
685 trace!(?rate, "Begin event");
686
687 idms_prox_read.get_radiusauthtoken(&rate, ct)
688 }
689
690 #[instrument(
691 level = "info",
692 skip_all,
693 fields(uuid = ?eventid)
694 )]
695 pub async fn handle_internalunixusertokenread(
696 &self,
697 client_auth_info: ClientAuthInfo,
698 uuid_or_name: String,
699 eventid: Uuid,
700 ) -> Result<UnixUserToken, OperationError> {
701 let ct = duration_from_epoch_now();
702 let mut idms_prox_read = self.idms.proxy_read().await?;
703
704 let ident = idms_prox_read
705 .validate_client_auth_info_to_ident(client_auth_info, ct)
706 .map_err(|e| {
707 error!("Invalid identity: {:?}", e);
708 e
709 })?;
710
711 let target_uuid = idms_prox_read
712 .qs_read
713 .name_to_uuid(uuid_or_name.as_str())
714 .map_err(|e| {
715 let uuid_or_name_val = match uuid_or_name.is_empty() {
718 true => "<empty uuid_or_name>",
719 false => &uuid_or_name,
720 };
721 admin_info!(
722 err = ?e,
723 "Error resolving {} as gidnumber continuing ...",
724 uuid_or_name_val
725 );
726 e
727 })?;
728
729 let rate = match UnixUserTokenEvent::from_parts(ident, target_uuid) {
731 Ok(s) => s,
732 Err(e) => {
733 error!("Failed to begin unix token read: {:?}", e);
734 return Err(e);
735 }
736 };
737
738 trace!(?rate, "Begin event");
739
740 idms_prox_read.get_unixusertoken(&rate, ct)
741 }
742
743 #[instrument(
744 level = "info",
745 skip_all,
746 fields(uuid = ?eventid)
747 )]
748 pub async fn handle_internalunixgrouptokenread(
749 &self,
750 client_auth_info: ClientAuthInfo,
751 uuid_or_name: String,
752 eventid: Uuid,
753 ) -> Result<UnixGroupToken, OperationError> {
754 let ct = duration_from_epoch_now();
755 let mut idms_prox_read = self.idms.proxy_read().await?;
756 let ident = idms_prox_read
757 .validate_client_auth_info_to_ident(client_auth_info, ct)
758 .map_err(|e| {
759 error!("Invalid identity: {:?}", e);
760 e
761 })?;
762
763 let target_uuid = idms_prox_read
764 .qs_read
765 .name_to_uuid(uuid_or_name.as_str())
766 .map_err(|e| {
767 admin_info!(err = ?e, "Error resolving as gidnumber continuing");
768 e
769 })?;
770
771 let rate = match UnixGroupTokenEvent::from_parts(
773 ident,
775 target_uuid,
776 ) {
777 Ok(s) => s,
778 Err(e) => {
779 error!("Failed to begin unix group token read: {:?}", e);
780 return Err(e);
781 }
782 };
783
784 trace!(?rate, "Begin event");
785
786 idms_prox_read.get_unixgrouptoken(&rate)
787 }
788
789 #[instrument(
790 level = "info",
791 skip_all,
792 fields(uuid = ?eventid)
793 )]
794 pub async fn handle_internalsshkeyread(
795 &self,
796 client_auth_info: ClientAuthInfo,
797 uuid_or_name: String,
798 eventid: Uuid,
799 ) -> Result<Vec<String>, OperationError> {
800 let ct = duration_from_epoch_now();
801 let mut idms_prox_read = self.idms.proxy_read().await?;
802 let ident = idms_prox_read
803 .validate_client_auth_info_to_ident(client_auth_info, ct)
804 .map_err(|e| {
805 error!("Invalid identity: {:?}", e);
806 e
807 })?;
808 let target_uuid = idms_prox_read
809 .qs_read
810 .name_to_uuid(uuid_or_name.as_str())
811 .inspect_err(|err| {
812 error!(?err, "Error resolving id to target");
813 })?;
814
815 let srch = match SearchEvent::from_target_uuid_request(
817 ident,
818 target_uuid,
819 &idms_prox_read.qs_read,
820 ) {
821 Ok(s) => s,
822 Err(e) => {
823 error!("Failed to begin ssh key read: {:?}", e);
824 return Err(e);
825 }
826 };
827
828 trace!(?srch, "Begin event");
829
830 match idms_prox_read.qs_read.search_ext(&srch) {
831 Ok(mut entries) => {
832 let r = entries
833 .pop()
834 .and_then(|e| {
836 e.get_ava_iter_sshpubkeys(Attribute::SshPublicKey)
838 .map(|i| i.collect())
839 })
840 .unwrap_or_else(|| {
841 Vec::new()
843 });
844 Ok(r)
845 }
846 Err(e) => Err(e),
847 }
848 }
849
850 #[instrument(
851 level = "info",
852 skip_all,
853 fields(uuid = ?eventid)
854 )]
855 pub async fn handle_internalsshkeytagread(
856 &self,
857 client_auth_info: ClientAuthInfo,
858 uuid_or_name: String,
859 tag: String,
860 eventid: Uuid,
861 ) -> Result<Option<String>, OperationError> {
862 let ct = duration_from_epoch_now();
863 let mut idms_prox_read = self.idms.proxy_read().await?;
864 let ident = idms_prox_read
865 .validate_client_auth_info_to_ident(client_auth_info, ct)
866 .map_err(|e| {
867 error!("Invalid identity: {:?}", e);
868 e
869 })?;
870 let target_uuid = idms_prox_read
871 .qs_read
872 .name_to_uuid(uuid_or_name.as_str())
873 .inspect_err(|err| {
874 admin_info!(?err, "Error resolving id to target");
875 })?;
876
877 let srch = match SearchEvent::from_target_uuid_request(
879 ident,
880 target_uuid,
881 &idms_prox_read.qs_read,
882 ) {
883 Ok(s) => s,
884 Err(e) => {
885 error!("Failed to begin sshkey tag read: {:?}", e);
886 return Err(e);
887 }
888 };
889
890 trace!(?srch, "Begin event");
891
892 match idms_prox_read.qs_read.search_ext(&srch) {
893 Ok(mut entries) => {
894 let r = entries
895 .pop()
896 .map(|e| {
898 e.get_ava_set(Attribute::SshPublicKey).and_then(|vs| {
900 vs.get_ssh_tag(&tag).map(|pk| pk.to_string())
902 })
903 })
904 .unwrap_or_else(|| {
905 None
907 });
908 Ok(r)
909 }
910 Err(e) => Err(e),
911 }
912 }
913
914 #[instrument(
915 level = "info",
916 skip_all,
917 fields(uuid = ?eventid)
918 )]
919 pub async fn handle_service_account_api_token_get(
920 &self,
921 client_auth_info: ClientAuthInfo,
922 uuid_or_name: String,
923 eventid: Uuid,
924 ) -> Result<Vec<ApiToken>, OperationError> {
925 let ct = duration_from_epoch_now();
926 let mut idms_prox_read = self.idms.proxy_read().await?;
927 let ident = idms_prox_read
928 .validate_client_auth_info_to_ident(client_auth_info, ct)
929 .map_err(|e| {
930 error!("Invalid identity: {:?}", e);
931 e
932 })?;
933 let target = idms_prox_read
934 .qs_read
935 .name_to_uuid(uuid_or_name.as_str())
936 .inspect_err(|err| {
937 error!(?err, "Error resolving id to target");
938 })?;
939
940 let lte = ListApiTokenEvent { ident, target };
941
942 idms_prox_read.service_account_list_api_token(<e)
943 }
944
945 #[instrument(
946 level = "info",
947 skip_all,
948 fields(uuid = ?eventid)
949 )]
950 pub async fn handle_account_user_auth_token_get(
951 &self,
952 client_auth_info: ClientAuthInfo,
953 uuid_or_name: String,
954 eventid: Uuid,
955 ) -> Result<Vec<UatStatus>, OperationError> {
956 let ct = duration_from_epoch_now();
957 let mut idms_prox_read = self.idms.proxy_read().await?;
958 let ident = idms_prox_read
959 .validate_client_auth_info_to_ident(client_auth_info, ct)
960 .map_err(|e| {
961 error!("Invalid identity: {:?}", e);
962 e
963 })?;
964 let target = idms_prox_read
965 .qs_read
966 .name_to_uuid(uuid_or_name.as_str())
967 .inspect_err(|err| {
968 error!(?err, "Error resolving id to target");
969 })?;
970
971 let lte = ListUserAuthTokenEvent { ident, target };
972
973 idms_prox_read.account_list_user_auth_tokens(<e)
974 }
975
976 #[instrument(
977 level = "info",
978 skip_all,
979 fields(uuid = ?eventid)
980 )]
981 pub async fn handle_user_identity_verification(
982 &self,
983 client_auth_info: ClientAuthInfo,
984 eventid: Uuid,
985 user_request: IdentifyUserRequest,
986 other_id: String,
987 ) -> Result<IdentifyUserResponse, OperationError> {
988 trace!("{:?}", &user_request);
989 let ct = duration_from_epoch_now();
990 let mut idms_prox_read = self.idms.proxy_read().await?;
991 let ident = idms_prox_read
992 .validate_client_auth_info_to_ident(client_auth_info, ct)
993 .map_err(|e| {
994 error!("Invalid identity: {:?}", e);
995 e
996 })?;
997 let target = idms_prox_read
998 .qs_read
999 .name_to_uuid(&other_id)
1000 .map_err(|e| {
1001 error!("No user found with the provided ID: {:?}", e);
1002 e
1003 })?;
1004 match user_request {
1005 IdentifyUserRequest::Start => idms_prox_read
1006 .handle_identify_user_start(&IdentifyUserStartEvent::new(target, ident), ct),
1007 IdentifyUserRequest::DisplayCode => idms_prox_read.handle_identify_user_display_code(
1008 &IdentifyUserDisplayCodeEvent::new(target, ident),
1009 ct,
1010 ),
1011 IdentifyUserRequest::SubmitCode { other_totp } => idms_prox_read
1012 .handle_identify_user_submit_code(
1013 &IdentifyUserSubmitCodeEvent::new(target, ident, other_totp),
1014 ct,
1015 ),
1016 }
1017 }
1018
1019 #[instrument(
1020 level = "info",
1021 skip_all,
1022 fields(uuid = ?eventid)
1023 )]
1024 pub async fn handle_idmaccountunixauth(
1025 &self,
1026 client_auth_info: ClientAuthInfo,
1027 uuid_or_name: String,
1028 cred: String,
1029 eventid: Uuid,
1030 ) -> Result<Option<UnixUserToken>, OperationError> {
1031 let ct = duration_from_epoch_now();
1032 let mut idm_auth = self.idms.auth().await?;
1033 let ident = idm_auth
1035 .validate_client_auth_info_to_ident(client_auth_info, ct)
1036 .map_err(|e| {
1037 error!(err = ?e, "Invalid identity");
1038 e
1039 })?;
1040
1041 let target_uuid = idm_auth
1042 .qs_read
1043 .name_to_uuid(uuid_or_name.as_str())
1044 .map_err(|e| {
1045 admin_info!(err = ?e, "Error resolving as gidnumber continuing");
1046 e
1047 })?;
1048 let uuae = match UnixUserAuthEvent::from_parts(ident, target_uuid, cred) {
1050 Ok(s) => s,
1051 Err(e) => {
1052 error!(err = ?e, "Failed to begin unix auth");
1053 return Err(e);
1054 }
1055 };
1056
1057 security_info!(event = ?uuae, "Begin unix auth event");
1058
1059 let res = idm_auth
1060 .auth_unix(&uuae, ct)
1061 .await
1062 .and_then(|r| idm_auth.commit().map(|_| r));
1063
1064 security_info!(?res, "Sending result");
1065
1066 res
1067 }
1068
1069 #[instrument(
1070 level = "info",
1071 skip_all,
1072 fields(uuid = ?eventid)
1073 )]
1074 pub async fn handle_idmcredentialstatus(
1075 &self,
1076 client_auth_info: ClientAuthInfo,
1077 uuid_or_name: String,
1078 eventid: Uuid,
1079 ) -> Result<CredentialStatus, OperationError> {
1080 let ct = duration_from_epoch_now();
1081 let mut idms_prox_read = self.idms.proxy_read().await?;
1082
1083 let ident = idms_prox_read
1084 .validate_client_auth_info_to_ident(client_auth_info, ct)
1085 .map_err(|e| {
1086 error!(err = ?e, "Invalid identity");
1087 e
1088 })?;
1089 let target_uuid = idms_prox_read
1090 .qs_read
1091 .name_to_uuid(uuid_or_name.as_str())
1092 .map_err(|e| {
1093 error!(err = ?e, "Error resolving id to target");
1094 e
1095 })?;
1096
1097 let cse = match CredentialStatusEvent::from_parts(
1099 ident,
1101 target_uuid,
1102 ) {
1103 Ok(s) => s,
1104 Err(e) => {
1105 error!(err = ?e, "Failed to begin credential status read");
1106 return Err(e);
1107 }
1108 };
1109
1110 trace!(?cse, "Begin event");
1111
1112 idms_prox_read.get_credentialstatus(&cse)
1113 }
1114
1115 #[instrument(
1116 level = "info",
1117 skip_all,
1118 fields(uuid = ?eventid)
1119 )]
1120 pub async fn handle_idmcredentialupdatestatus(
1121 &self,
1122 session_token: CUSessionToken,
1123 eventid: Uuid,
1124 ) -> Result<CUStatus, OperationError> {
1125 let session_token = JweCompact::from_str(&session_token.token)
1126 .map(|token_enc| CredentialUpdateSessionToken { token_enc })
1127 .map_err(|err| {
1128 error!(?err, "malformed token");
1129 OperationError::InvalidRequestState
1130 })?;
1131
1132 let ct = duration_from_epoch_now();
1134 let idms_cred_update = self.idms.cred_update_transaction().await?;
1135
1136 idms_cred_update
1137 .credential_update_status(&session_token, ct)
1138 .map_err(|e| {
1139 error!(
1140 err = ?e,
1141 "Failed to begin credential_update_status",
1142 );
1143 e
1144 })
1145 .map(|sta| sta.into())
1146 }
1147
1148 #[instrument(
1149 level = "info",
1150 skip_all,
1151 fields(uuid = ?eventid)
1152 )]
1153 pub async fn handle_idmcredentialupdate(
1154 &self,
1155 session_token: CUSessionToken,
1156 scr: CURequest,
1157 eventid: Uuid,
1158 ) -> Result<CUStatus, OperationError> {
1159 let session_token = JweCompact::from_str(&session_token.token)
1160 .map(|token_enc| CredentialUpdateSessionToken { token_enc })
1161 .map_err(|err| {
1162 error!(?err, "Invalid Token - Must be a compact JWE");
1163 OperationError::InvalidRequestState
1164 })?;
1165
1166 let ct = duration_from_epoch_now();
1167 let idms_cred_update = self.idms.cred_update_transaction().await?;
1168
1169 debug!(?scr);
1170
1171 match scr {
1172 CURequest::PrimaryRemove => idms_cred_update
1173 .credential_primary_delete(&session_token, ct)
1174 .map_err(|e| {
1175 error!(
1176 err = ?e,
1177 "Failed to begin credential_primary_delete",
1178 );
1179 e
1180 }),
1181 CURequest::Password(pw) => idms_cred_update
1182 .credential_primary_set_password(&session_token, ct, &pw)
1183 .map_err(|e| {
1184 error!(
1185 err = ?e,
1186 "Failed to begin credential_primary_set_password",
1187 );
1188 e
1189 }),
1190 CURequest::CancelMFAReg => idms_cred_update
1191 .credential_update_cancel_mfareg(&session_token, ct)
1192 .map_err(|e| {
1193 error!(
1194 err = ?e,
1195 "Failed to begin credential_update_cancel_mfareg",
1196 );
1197 e
1198 }),
1199 CURequest::TotpGenerate => idms_cred_update
1200 .credential_primary_init_totp(&session_token, ct)
1201 .map_err(|e| {
1202 error!(
1203 err = ?e,
1204 "Failed to begin credential_primary_init_totp",
1205 );
1206 e
1207 }),
1208 CURequest::TotpVerify(totp_chal, label) => idms_cred_update
1209 .credential_primary_check_totp(&session_token, ct, totp_chal, &label)
1210 .map_err(|e| {
1211 error!(
1212 err = ?e,
1213 "Failed to begin credential_primary_check_totp",
1214 );
1215 e
1216 }),
1217 CURequest::TotpAcceptSha1 => idms_cred_update
1218 .credential_primary_accept_sha1_totp(&session_token, ct)
1219 .map_err(|e| {
1220 error!(
1221 err = ?e,
1222 "Failed to begin credential_primary_accept_sha1_totp",
1223 );
1224 e
1225 }),
1226 CURequest::TotpRemove(label) => idms_cred_update
1227 .credential_primary_remove_totp(&session_token, ct, &label)
1228 .map_err(|e| {
1229 error!(
1230 err = ?e,
1231 "Failed to begin credential_primary_remove_totp",
1232 );
1233 e
1234 }),
1235 CURequest::BackupCodeGenerate => idms_cred_update
1236 .credential_primary_init_backup_codes(&session_token, ct)
1237 .map_err(|e| {
1238 error!(
1239 err = ?e,
1240 "Failed to begin credential_primary_init_backup_codes",
1241 );
1242 e
1243 }),
1244 CURequest::BackupCodeRemove => idms_cred_update
1245 .credential_primary_remove_backup_codes(&session_token, ct)
1246 .map_err(|e| {
1247 error!(
1248 err = ?e,
1249 "Failed to begin credential_primary_remove_backup_codes",
1250 );
1251 e
1252 }),
1253 CURequest::PasskeyInit => idms_cred_update
1254 .credential_passkey_init(&session_token, ct)
1255 .map_err(|e| {
1256 error!(
1257 err = ?e,
1258 "Failed to begin credential_passkey_init",
1259 );
1260 e
1261 }),
1262 CURequest::PasskeyFinish(label, rpkc) => idms_cred_update
1263 .credential_passkey_finish(&session_token, ct, label, &rpkc)
1264 .map_err(|e| {
1265 error!(
1266 err = ?e,
1267 "Failed to begin credential_passkey_finish",
1268 );
1269 e
1270 }),
1271 CURequest::PasskeyRemove(uuid) => idms_cred_update
1272 .credential_passkey_remove(&session_token, ct, uuid)
1273 .map_err(|e| {
1274 error!(
1275 err = ?e,
1276 "Failed to begin credential_passkey_remove"
1277 );
1278 e
1279 }),
1280 CURequest::AttestedPasskeyInit => idms_cred_update
1281 .credential_attested_passkey_init(&session_token, ct)
1282 .map_err(|e| {
1283 error!(
1284 err = ?e,
1285 "Failed to begin credential_attested_passkey_init"
1286 );
1287 e
1288 }),
1289 CURequest::AttestedPasskeyFinish(label, rpkc) => idms_cred_update
1290 .credential_attested_passkey_finish(&session_token, ct, label, &rpkc)
1291 .map_err(|e| {
1292 error!(
1293 err = ?e,
1294 "Failed to begin credential_attested_passkey_finish"
1295 );
1296 e
1297 }),
1298 CURequest::AttestedPasskeyRemove(uuid) => idms_cred_update
1299 .credential_attested_passkey_remove(&session_token, ct, uuid)
1300 .map_err(|e| {
1301 error!(
1302 err = ?e,
1303 "Failed to begin credential_attested_passkey_remove"
1304 );
1305 e
1306 }),
1307 CURequest::UnixPasswordRemove => idms_cred_update
1308 .credential_unix_delete(&session_token, ct)
1309 .inspect_err(|err| {
1310 error!(?err, "Failed to begin credential_unix_delete");
1311 }),
1312 CURequest::UnixPassword(pw) => idms_cred_update
1313 .credential_unix_set_password(&session_token, ct, &pw)
1314 .inspect_err(|err| {
1315 error!(?err, "Failed to begin credential_unix_set_password");
1316 }),
1317
1318 CURequest::SshPublicKey(label, pubkey) => idms_cred_update
1319 .credential_sshkey_add(&session_token, ct, label, pubkey)
1320 .inspect_err(|err| {
1321 error!(?err, "Failed to begin credential_sshkey_remove");
1322 }),
1323
1324 CURequest::SshPublicKeyRemove(label) => idms_cred_update
1325 .credential_sshkey_remove(&session_token, ct, &label)
1326 .inspect_err(|err| {
1327 error!(?err, "Failed to begin credential_sshkey_remove");
1328 }),
1329 }
1330 .map(|sta| sta.into())
1331 }
1332
1333 #[instrument(
1334 level = "info",
1335 skip_all,
1336 fields(uuid = ?eventid)
1337 )]
1338 pub async fn handle_oauth2_basic_secret_read(
1339 &self,
1340 client_auth_info: ClientAuthInfo,
1341 filter: Filter<FilterInvalid>,
1342 eventid: Uuid,
1343 ) -> Result<Option<String>, OperationError> {
1344 let ct = duration_from_epoch_now();
1345 let mut idms_prox_read = self.idms.proxy_read().await?;
1346 let ident = idms_prox_read
1347 .validate_client_auth_info_to_ident(client_auth_info, ct)
1348 .map_err(|e| {
1349 error!("Invalid identity: {:?}", e);
1350 e
1351 })?;
1352
1353 let srch = match SearchEvent::from_internal_message(
1355 ident,
1356 &filter,
1357 None,
1358 &mut idms_prox_read.qs_read,
1359 ) {
1360 Ok(s) => s,
1361 Err(e) => {
1362 error!("Failed to begin oauth2 basic secret read: {:?}", e);
1363 return Err(e);
1364 }
1365 };
1366
1367 trace!(?srch, "Begin event");
1368
1369 match idms_prox_read.qs_read.search_ext(&srch) {
1371 Ok(mut entries) => {
1372 let r = entries
1373 .pop()
1374 .and_then(|entry| {
1376 entry
1377 .get_ava_single(Attribute::OAuth2RsBasicSecret)
1378 .and_then(|v| v.get_secret_str().map(str::to_string))
1379 });
1380 Ok(r)
1381 }
1382 Err(e) => Err(e),
1383 }
1384 }
1385
1386 #[instrument(
1387 level = "info",
1388 skip_all,
1389 fields(uuid = ?eventid)
1390 )]
1391 pub async fn handle_oauth2_authorise(
1392 &self,
1393 client_auth_info: ClientAuthInfo,
1394 auth_req: AuthorisationRequest,
1395 eventid: Uuid,
1396 ) -> Result<AuthoriseResponse, Oauth2Error> {
1397 let ct = duration_from_epoch_now();
1398 let mut idms_prox_read = self
1399 .idms
1400 .proxy_read()
1401 .await
1402 .map_err(Oauth2Error::ServerError)?;
1403 let ident = idms_prox_read
1404 .validate_client_auth_info_to_ident(client_auth_info, ct)
1405 .inspect_err(|e| {
1406 error!("Invalid identity: {:?}", e);
1407 })
1408 .ok();
1409
1410 idms_prox_read.check_oauth2_authorisation(ident.as_ref(), &auth_req, ct)
1412 }
1413
1414 #[instrument(
1415 level = "info",
1416 skip_all,
1417 fields(uuid = ?eventid)
1418 )]
1419 pub async fn handle_oauth2_authorise_reject(
1420 &self,
1421 client_auth_info: ClientAuthInfo,
1422 consent_req: String,
1423 eventid: Uuid,
1424 ) -> Result<AuthoriseReject, OperationError> {
1425 let ct = duration_from_epoch_now();
1426 let mut idms_prox_read = self.idms.proxy_read().await?;
1427 let ident = idms_prox_read
1428 .validate_client_auth_info_to_ident(client_auth_info, ct)
1429 .map_err(|e| {
1430 error!("Invalid identity: {:?}", e);
1431 e
1432 })?;
1433
1434 idms_prox_read.check_oauth2_authorise_reject(&ident, &consent_req, ct)
1435 }
1436
1437 #[instrument(
1438 level = "info",
1439 skip_all,
1440 fields(uuid = ?eventid)
1441 )]
1442 pub async fn handle_oauth2_token_introspect(
1443 &self,
1444 client_auth_info: ClientAuthInfo,
1445 intr_req: AccessTokenIntrospectRequest,
1446 eventid: Uuid,
1447 ) -> Result<AccessTokenIntrospectResponse, Oauth2Error> {
1448 let ct = duration_from_epoch_now();
1449 let mut idms_prox_read = self
1450 .idms
1451 .proxy_read()
1452 .await
1453 .map_err(Oauth2Error::ServerError)?;
1454 idms_prox_read.check_oauth2_token_introspect(&client_auth_info, &intr_req, ct)
1456 }
1457
1458 #[instrument(
1459 level = "info",
1460 skip_all,
1461 fields(uuid = ?eventid)
1462 )]
1463 pub async fn handle_oauth2_openid_userinfo(
1464 &self,
1465 client_id: String,
1466 token: &JwsCompact,
1467 eventid: Uuid,
1468 ) -> Result<OidcToken, Oauth2Error> {
1469 let ct = duration_from_epoch_now();
1470 let mut idms_prox_read = self
1471 .idms
1472 .proxy_read()
1473 .await
1474 .map_err(Oauth2Error::ServerError)?;
1475 idms_prox_read.oauth2_openid_userinfo(&client_id, token, ct)
1476 }
1477
1478 #[instrument(
1479 level = "info",
1480 skip_all,
1481 fields(uuid = ?eventid)
1482 )]
1483 pub async fn handle_oauth2_openid_discovery(
1484 &self,
1485 client_id: String,
1486 eventid: Uuid,
1487 ) -> Result<OidcDiscoveryResponse, OperationError> {
1488 let idms_prox_read = self.idms.proxy_read().await?;
1489 idms_prox_read.oauth2_openid_discovery(&client_id)
1490 }
1491
1492 #[instrument(
1493 level = "info",
1494 skip_all,
1495 fields(uuid = ?eventid)
1496 )]
1497 pub async fn handle_oauth2_webfinger_discovery(
1498 &self,
1499 client_id: &str,
1500 resource_id: &str,
1501 eventid: Uuid,
1502 ) -> Result<OidcWebfingerResponse, OperationError> {
1503 let mut idms_prox_read = self.idms.proxy_read().await?;
1504 idms_prox_read.oauth2_openid_webfinger(client_id, resource_id)
1505 }
1506
1507 #[instrument(
1508 level = "info",
1509 skip_all,
1510 fields(uuid = ?eventid)
1511 )]
1512 pub async fn handle_oauth2_rfc8414_metadata(
1513 &self,
1514 client_id: String,
1515 eventid: Uuid,
1516 ) -> Result<Oauth2Rfc8414MetadataResponse, OperationError> {
1517 let idms_prox_read = self.idms.proxy_read().await?;
1518 idms_prox_read.oauth2_rfc8414_metadata(&client_id)
1519 }
1520
1521 #[instrument(
1522 level = "info",
1523 skip_all,
1524 fields(uuid = ?eventid)
1525 )]
1526 pub async fn handle_oauth2_openid_publickey(
1527 &self,
1528 client_id: String,
1529 eventid: Uuid,
1530 ) -> Result<JwkKeySet, OperationError> {
1531 let idms_prox_read = self.idms.proxy_read().await?;
1532 idms_prox_read.oauth2_openid_publickey(&client_id)
1533 }
1534
1535 #[instrument(
1536 level = "info",
1537 skip_all,
1538 fields(uuid = ?eventid)
1539 )]
1540 pub async fn handle_list_applinks(
1541 &self,
1542 client_auth_info: ClientAuthInfo,
1543 eventid: Uuid,
1544 ) -> Result<Vec<AppLink>, OperationError> {
1545 let ct = duration_from_epoch_now();
1546 let mut idms_prox_read = self.idms.proxy_read().await?;
1547 let ident = idms_prox_read
1548 .validate_client_auth_info_to_ident(client_auth_info, ct)
1549 .map_err(|e| {
1550 error!("Invalid identity: {:?}", e);
1551 e
1552 })?;
1553
1554 idms_prox_read.list_applinks(&ident)
1556 }
1557
1558 #[instrument(
1559 level = "info",
1560 skip_all,
1561 fields(uuid = ?eventid)
1562 )]
1563 pub async fn handle_auth_valid(
1564 &self,
1565 client_auth_info: ClientAuthInfo,
1566 eventid: Uuid,
1567 ) -> Result<(), OperationError> {
1568 let ct = duration_from_epoch_now();
1569 let mut idms_prox_read = self.idms.proxy_read().await?;
1570
1571 idms_prox_read
1572 .validate_client_auth_info_to_ident(client_auth_info, ct)
1573 .map(|_| ())
1574 .map_err(|e| {
1575 error!("Invalid identity: {:?}", e);
1576 e
1577 })
1578 }
1579
1580 #[instrument(
1581 level = "info",
1582 skip_all,
1583 fields(uuid = ?eventid)
1584 )]
1585 pub async fn handle_public_jwk_get(
1587 &self,
1588 key_id: String,
1589 eventid: Uuid,
1590 ) -> Result<Jwk, OperationError> {
1591 let mut idms_prox_read = self.idms.proxy_read().await?;
1592
1593 idms_prox_read.jws_public_jwk(key_id.as_str())
1594 }
1595
1596 #[instrument(
1597 level = "info",
1598 skip_all,
1599 fields(uuid = ?eventid)
1600 )]
1601 pub async fn handle_ldaprequest(
1602 &self,
1603 eventid: Uuid,
1604 protomsg: LdapMsg,
1605 uat: Option<LdapBoundToken>,
1606 ip_addr: IpAddr,
1607 ) -> Option<LdapResponseState> {
1608 let res = match ServerOps::try_from(protomsg) {
1609 Ok(server_op) => self
1610 .ldap
1611 .do_op(&self.idms, server_op, uat, ip_addr, eventid)
1612 .await
1613 .unwrap_or_else(|e| {
1614 error!("do_op failed -> {:?}", e);
1615 LdapResponseState::Disconnect(DisconnectionNotice::gen(
1616 LdapResultCode::Other,
1617 format!("Internal Server Error {:?}", &eventid).as_str(),
1618 ))
1619 }),
1620 Err(_) => LdapResponseState::Disconnect(DisconnectionNotice::gen(
1621 LdapResultCode::ProtocolError,
1622 format!("Invalid Request {:?}", &eventid).as_str(),
1623 )),
1624 };
1625 Some(res)
1626 }
1627
1628 pub fn domain_info_read(&self) -> DomainInfoRead {
1629 self.idms.domain_read()
1630 }
1631}