1use compact_jwt::{JweCompact, Jwk, JwsCompact};
2use kanidm_proto::backup::BackupCompression;
3use kanidm_proto::internal::{
4    ApiToken, AppLink, CURequest, CUSessionToken, CUStatus, CredentialStatus, IdentifyUserRequest,
5    IdentifyUserResponse, ImageValue, OperationError, RadiusAuthToken, SearchRequest,
6    SearchResponse, UserAuthToken,
7};
8use kanidm_proto::oauth2::OidcWebfingerResponse;
9use kanidm_proto::v1::{
10    AuthIssueSession, Entry as ProtoEntry, UatStatus, UnixGroupToken, UnixUserToken, WhoamiResponse,
11};
12use kanidmd_lib::be::BackendTransaction;
13use kanidmd_lib::idm::identityverification::{
14    IdentifyUserDisplayCodeEvent, IdentifyUserStartEvent, IdentifyUserSubmitCodeEvent,
15};
16use kanidmd_lib::prelude::*;
17use kanidmd_lib::{
18    event::{OnlineBackupEvent, SearchEvent, SearchResult, WhoamiResult},
19    filter::{Filter, FilterInvalid},
20    idm::account::ListUserAuthTokenEvent,
21    idm::authentication::AuthStep,
22    idm::credupdatesession::CredentialUpdateSessionToken,
23    idm::event::{
24        AuthEvent, AuthResult, CredentialStatusEvent, RadiusAuthTokenEvent, UnixGroupTokenEvent,
25        UnixUserAuthEvent, UnixUserTokenEvent,
26    },
27    idm::ldap::{LdapBoundToken, LdapResponseState},
28    idm::oauth2::{
29        AccessTokenIntrospectRequest, AccessTokenIntrospectResponse, AuthorisationRequest,
30        AuthoriseReject, AuthoriseResponse, JwkKeySet, Oauth2Error, Oauth2Rfc8414MetadataResponse,
31        OidcDiscoveryResponse, OidcToken,
32    },
33    idm::server::{DomainInfoRead, IdmServerTransaction},
34    idm::serviceaccount::ListApiTokenEvent,
35};
36use ldap3_proto::simple::*;
37use regex::Regex;
38use std::convert::TryFrom;
39use std::fs;
40use std::net::IpAddr;
41use std::path::{Path, PathBuf};
42use std::str::FromStr;
43use tracing::{error, info, instrument, trace};
44use uuid::Uuid;
45
46use super::QueryServerReadV1;
47
48impl QueryServerReadV1 {
51    #[instrument(
61        level = "info",
62        name = "search",
63        skip_all,
64        fields(uuid = ?eventid)
65    )]
66    pub async fn handle_search(
67        &self,
68        client_auth_info: ClientAuthInfo,
69        req: SearchRequest,
70        eventid: Uuid,
71    ) -> Result<SearchResponse, OperationError> {
72        let ct = duration_from_epoch_now();
74        let mut idms_prox_read = self.idms.proxy_read().await?;
75        let ident = idms_prox_read
76            .validate_client_auth_info_to_ident(client_auth_info, ct)
77            .map_err(|e| {
78                error!(?e, "Invalid identity");
79                e
80            })?;
81
82        let search =
84            SearchEvent::from_message(ident, &req, &mut idms_prox_read.qs_read).map_err(|e| {
85                error!(?e, "Failed to begin search");
86                e
87            })?;
88
89        trace!(?search, "Begin event");
90
91        let entries = idms_prox_read.qs_read.search_ext(&search)?;
92
93        SearchResult::new(&mut idms_prox_read.qs_read, &entries).map(SearchResult::response)
94    }
95
96    #[instrument(
97        level = "info",
98        name = "auth",
99        skip_all,
100        fields(uuid = ?eventid)
101    )]
102    pub async fn handle_auth(
103        &self,
104        sessionid: Option<Uuid>,
105        req: AuthStep,
106        eventid: Uuid,
107        client_auth_info: ClientAuthInfo,
108    ) -> Result<AuthResult, OperationError> {
109        let ct = duration_from_epoch_now();
114        let mut idm_auth = self.idms.auth().await?;
115        security_info!(?sessionid, ?req, "Begin auth event");
116
117        let ae = AuthEvent::from_message(sessionid, req).map_err(|e| {
121            error!(err = ?e, "Failed to parse AuthEvent");
122            e
123        })?;
124
125        idm_auth.expire_auth_sessions(ct).await;
129
130        let res = idm_auth
133            .auth(&ae, ct, client_auth_info)
134            .await
135            .and_then(|r| idm_auth.commit().map(|_| r));
136
137        security_info!(?res, "Sending auth result");
138
139        res
140    }
141
142    #[instrument(
143        level = "info",
144        name = "reauth",
145        skip_all,
146        fields(uuid = ?eventid)
147    )]
148    pub async fn handle_reauth(
149        &self,
150        client_auth_info: ClientAuthInfo,
151        issue: AuthIssueSession,
152        eventid: Uuid,
153    ) -> Result<AuthResult, OperationError> {
154        let ct = duration_from_epoch_now();
155        let mut idm_auth = self.idms.auth().await?;
156        security_info!("Begin reauth event");
157
158        let ident = idm_auth
159            .validate_client_auth_info_to_ident(client_auth_info.clone(), ct)
160            .map_err(|e| {
161                error!(?e, "Invalid identity");
162                e
163            })?;
164
165        idm_auth.expire_auth_sessions(ct).await;
169
170        let res = idm_auth
173            .reauth_init(ident, issue, ct, client_auth_info)
174            .await
175            .and_then(|r| idm_auth.commit().map(|_| r));
176
177        security_info!(?res, "Sending reauth result");
178
179        res
180    }
181
182    #[instrument(
183        level = "info",
184        name = "online_backup",
185        skip_all,
186        fields(uuid = ?msg.eventid)
187    )]
188    pub async fn handle_online_backup(
189        &self,
190        msg: OnlineBackupEvent,
191        outpath: &Path,
192        versions: usize,
193        compression: BackupCompression,
194    ) -> Result<(), OperationError> {
195        trace!(eventid = ?msg.eventid, "Begin online backup event");
196
197        let now = time::OffsetDateTime::now_utc();
198
199        #[allow(clippy::unwrap_used)]
200        let timestamp = now.format(&Rfc3339).unwrap();
201        let dest_file = outpath.join(format!("backup-{timestamp}.json{}", compression.suffix()));
202
203        if dest_file.exists() {
204            error!(
205                "Online backup file {} already exists, will not overwrite it.",
206                dest_file.display()
207            );
208            return Err(OperationError::InvalidState);
209        }
210
211        {
213            let mut idms_prox_read = self.idms.proxy_read().await?;
214            idms_prox_read
215                .qs_read
216                .get_be_txn()
217                .backup(&dest_file, compression)
218                .map(|()| {
219                    info!("Online backup created {} successfully", dest_file.display());
220                })
221                .map_err(|e| {
222                    error!(
223                        "Online backup failed to create {}: {:?}",
224                        dest_file.display(),
225                        e
226                    );
227                    OperationError::InvalidState
228                })?;
229        }
230
231        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                .inspect_err(|err| {
1175                    error!(?err, "Failed to begin credential_primary_delete",);
1176                }),
1177            CURequest::PasswordQualityCheck(pw) => idms_cred_update
1178                .credential_check_password_quality(&session_token, ct, &pw)
1179                .inspect_err(|err| {
1180                    error!(?err, "Failed to begin credential_check_password_quality",);
1181                }),
1182            CURequest::Password(pw) => idms_cred_update
1183                .credential_primary_set_password(&session_token, ct, &pw)
1184                .inspect_err(|err| {
1185                    error!(?err, "Failed to begin credential_primary_set_password",);
1186                }),
1187            CURequest::CancelMFAReg => idms_cred_update
1188                .credential_update_cancel_mfareg(&session_token, ct)
1189                .inspect_err(|err| {
1190                    error!(?err, "Failed to begin credential_update_cancel_mfareg",);
1191                }),
1192            CURequest::TotpGenerate => idms_cred_update
1193                .credential_primary_init_totp(&session_token, ct)
1194                .inspect_err(|err| {
1195                    error!(?err, "Failed to begin credential_primary_init_totp",);
1196                }),
1197            CURequest::TotpVerify(totp_chal, label) => idms_cred_update
1198                .credential_primary_check_totp(&session_token, ct, totp_chal, &label)
1199                .inspect_err(|err| {
1200                    error!(?err, "Failed to begin credential_primary_check_totp",);
1201                }),
1202            CURequest::TotpAcceptSha1 => idms_cred_update
1203                .credential_primary_accept_sha1_totp(&session_token, ct)
1204                .inspect_err(|err| {
1205                    error!(?err, "Failed to begin credential_primary_accept_sha1_totp",);
1206                }),
1207            CURequest::TotpRemove(label) => idms_cred_update
1208                .credential_primary_remove_totp(&session_token, ct, &label)
1209                .inspect_err(|err| {
1210                    error!(?err, "Failed to begin credential_primary_remove_totp",);
1211                }),
1212            CURequest::BackupCodeGenerate => idms_cred_update
1213                .credential_primary_init_backup_codes(&session_token, ct)
1214                .inspect_err(|err| {
1215                    error!(?err, "Failed to begin credential_primary_init_backup_codes",);
1216                }),
1217            CURequest::BackupCodeRemove => idms_cred_update
1218                .credential_primary_remove_backup_codes(&session_token, ct)
1219                .inspect_err(|err| {
1220                    error!(
1221                        ?err,
1222                        "Failed to begin credential_primary_remove_backup_codes",
1223                    );
1224                }),
1225            CURequest::PasskeyInit => idms_cred_update
1226                .credential_passkey_init(&session_token, ct)
1227                .inspect_err(|err| {
1228                    error!(?err, "Failed to begin credential_passkey_init",);
1229                }),
1230            CURequest::PasskeyFinish(label, rpkc) => idms_cred_update
1231                .credential_passkey_finish(&session_token, ct, label, &rpkc)
1232                .inspect_err(|err| {
1233                    error!(?err, "Failed to begin credential_passkey_finish",);
1234                }),
1235            CURequest::PasskeyRemove(uuid) => idms_cred_update
1236                .credential_passkey_remove(&session_token, ct, uuid)
1237                .inspect_err(|err| {
1238                    error!(?err, "Failed to begin credential_passkey_remove",);
1239                }),
1240            CURequest::AttestedPasskeyInit => idms_cred_update
1241                .credential_attested_passkey_init(&session_token, ct)
1242                .inspect_err(|err| {
1243                    error!(?err, "Failed to begin credential_attested_passkey_init",);
1244                }),
1245            CURequest::AttestedPasskeyFinish(label, rpkc) => idms_cred_update
1246                .credential_attested_passkey_finish(&session_token, ct, label, &rpkc)
1247                .inspect_err(|err| {
1248                    error!(?err, "Failed to begin credential_attested_passkey_finish",);
1249                }),
1250            CURequest::AttestedPasskeyRemove(uuid) => idms_cred_update
1251                .credential_attested_passkey_remove(&session_token, ct, uuid)
1252                .inspect_err(|err| {
1253                    error!(?err, "Failed to begin credential_attested_passkey_remove",);
1254                }),
1255            CURequest::UnixPasswordRemove => idms_cred_update
1256                .credential_unix_delete(&session_token, ct)
1257                .inspect_err(|err| {
1258                    error!(?err, "Failed to begin credential_unix_delete");
1259                }),
1260            CURequest::UnixPassword(pw) => idms_cred_update
1261                .credential_unix_set_password(&session_token, ct, &pw)
1262                .inspect_err(|err| {
1263                    error!(?err, "Failed to begin credential_unix_set_password");
1264                }),
1265            CURequest::SshPublicKey(label, pubkey) => idms_cred_update
1266                .credential_sshkey_add(&session_token, ct, label, pubkey)
1267                .inspect_err(|err| {
1268                    error!(?err, "Failed to begin credential_sshkey_remove");
1269                }),
1270            CURequest::SshPublicKeyRemove(label) => idms_cred_update
1271                .credential_sshkey_remove(&session_token, ct, &label)
1272                .inspect_err(|err| {
1273                    error!(?err, "Failed to begin credential_sshkey_remove");
1274                }),
1275        }
1276        .map(|sta| sta.into())
1277    }
1278
1279    #[instrument(
1280        level = "info",
1281        skip_all,
1282        fields(uuid = ?eventid)
1283    )]
1284    pub async fn handle_oauth2_basic_secret_read(
1285        &self,
1286        client_auth_info: ClientAuthInfo,
1287        filter: Filter<FilterInvalid>,
1288        eventid: Uuid,
1289    ) -> Result<Option<String>, OperationError> {
1290        let ct = duration_from_epoch_now();
1291        let mut idms_prox_read = self.idms.proxy_read().await?;
1292        let ident = idms_prox_read
1293            .validate_client_auth_info_to_ident(client_auth_info, ct)
1294            .map_err(|e| {
1295                error!("Invalid identity: {:?}", e);
1296                e
1297            })?;
1298
1299        let srch = match SearchEvent::from_internal_message(
1301            ident,
1302            &filter,
1303            None,
1304            &mut idms_prox_read.qs_read,
1305        ) {
1306            Ok(s) => s,
1307            Err(e) => {
1308                error!("Failed to begin oauth2 basic secret read: {:?}", e);
1309                return Err(e);
1310            }
1311        };
1312
1313        trace!(?srch, "Begin event");
1314
1315        match idms_prox_read.qs_read.search_ext(&srch) {
1317            Ok(mut entries) => {
1318                let r = entries
1319                    .pop()
1320                    .and_then(|entry| {
1322                        entry
1323                            .get_ava_single(Attribute::OAuth2RsBasicSecret)
1324                            .and_then(|v| v.get_secret_str().map(str::to_string))
1325                    });
1326                Ok(r)
1327            }
1328            Err(e) => Err(e),
1329        }
1330    }
1331
1332    #[instrument(
1333        level = "info",
1334        skip_all,
1335        fields(uuid = ?eventid)
1336    )]
1337    pub async fn handle_oauth2_authorise(
1338        &self,
1339        client_auth_info: ClientAuthInfo,
1340        auth_req: AuthorisationRequest,
1341        eventid: Uuid,
1342    ) -> Result<AuthoriseResponse, Oauth2Error> {
1343        let ct = duration_from_epoch_now();
1344        let mut idms_prox_read = self
1345            .idms
1346            .proxy_read()
1347            .await
1348            .map_err(Oauth2Error::ServerError)?;
1349        let ident = idms_prox_read
1350            .validate_client_auth_info_to_ident(client_auth_info, ct)
1351            .inspect_err(|e| {
1352                error!("Invalid identity: {:?}", e);
1353            })
1354            .ok();
1355
1356        idms_prox_read.check_oauth2_authorisation(ident.as_ref(), &auth_req, ct)
1358    }
1359
1360    #[instrument(
1361        level = "info",
1362        skip_all,
1363        fields(uuid = ?eventid)
1364    )]
1365    pub async fn handle_oauth2_authorise_reject(
1366        &self,
1367        client_auth_info: ClientAuthInfo,
1368        consent_req: String,
1369        eventid: Uuid,
1370    ) -> Result<AuthoriseReject, OperationError> {
1371        let ct = duration_from_epoch_now();
1372        let mut idms_prox_read = self.idms.proxy_read().await?;
1373        let ident = idms_prox_read
1374            .validate_client_auth_info_to_ident(client_auth_info, ct)
1375            .map_err(|e| {
1376                error!("Invalid identity: {:?}", e);
1377                e
1378            })?;
1379
1380        idms_prox_read.check_oauth2_authorise_reject(&ident, &consent_req, ct)
1381    }
1382
1383    #[instrument(
1384        level = "info",
1385        skip_all,
1386        fields(uuid = ?eventid)
1387    )]
1388    pub async fn handle_oauth2_token_introspect(
1389        &self,
1390        client_auth_info: ClientAuthInfo,
1391        intr_req: AccessTokenIntrospectRequest,
1392        eventid: Uuid,
1393    ) -> Result<AccessTokenIntrospectResponse, Oauth2Error> {
1394        let ct = duration_from_epoch_now();
1395        let mut idms_prox_read = self
1396            .idms
1397            .proxy_read()
1398            .await
1399            .map_err(Oauth2Error::ServerError)?;
1400        idms_prox_read.check_oauth2_token_introspect(&client_auth_info, &intr_req, ct)
1402    }
1403
1404    #[instrument(
1405        level = "info",
1406        skip_all,
1407        fields(uuid = ?eventid)
1408    )]
1409    pub async fn handle_oauth2_openid_userinfo(
1410        &self,
1411        client_id: String,
1412        token: &JwsCompact,
1413        eventid: Uuid,
1414    ) -> Result<OidcToken, Oauth2Error> {
1415        let ct = duration_from_epoch_now();
1416        let mut idms_prox_read = self
1417            .idms
1418            .proxy_read()
1419            .await
1420            .map_err(Oauth2Error::ServerError)?;
1421        idms_prox_read.oauth2_openid_userinfo(&client_id, token, ct)
1422    }
1423
1424    #[instrument(
1425        level = "info",
1426        skip_all,
1427        fields(uuid = ?eventid)
1428    )]
1429    pub async fn handle_oauth2_openid_discovery(
1430        &self,
1431        client_id: String,
1432        eventid: Uuid,
1433    ) -> Result<OidcDiscoveryResponse, OperationError> {
1434        let idms_prox_read = self.idms.proxy_read().await?;
1435        idms_prox_read.oauth2_openid_discovery(&client_id)
1436    }
1437
1438    #[instrument(
1439        level = "info",
1440        skip_all,
1441        fields(uuid = ?eventid)
1442    )]
1443    pub async fn handle_oauth2_webfinger_discovery(
1444        &self,
1445        client_id: &str,
1446        resource_id: &str,
1447        eventid: Uuid,
1448    ) -> Result<OidcWebfingerResponse, OperationError> {
1449        let mut idms_prox_read = self.idms.proxy_read().await?;
1450        idms_prox_read.oauth2_openid_webfinger(client_id, resource_id)
1451    }
1452
1453    #[instrument(
1454        level = "info",
1455        skip_all,
1456        fields(uuid = ?eventid)
1457    )]
1458    pub async fn handle_oauth2_rfc8414_metadata(
1459        &self,
1460        client_id: String,
1461        eventid: Uuid,
1462    ) -> Result<Oauth2Rfc8414MetadataResponse, OperationError> {
1463        let idms_prox_read = self.idms.proxy_read().await?;
1464        idms_prox_read.oauth2_rfc8414_metadata(&client_id)
1465    }
1466
1467    #[instrument(
1468        level = "info",
1469        skip_all,
1470        fields(uuid = ?eventid)
1471    )]
1472    pub async fn handle_oauth2_openid_publickey(
1473        &self,
1474        client_id: String,
1475        eventid: Uuid,
1476    ) -> Result<JwkKeySet, OperationError> {
1477        let idms_prox_read = self.idms.proxy_read().await?;
1478        idms_prox_read.oauth2_openid_publickey(&client_id)
1479    }
1480
1481    #[instrument(
1482        level = "info",
1483        skip_all,
1484        fields(uuid = ?eventid)
1485    )]
1486    pub async fn handle_list_applinks(
1487        &self,
1488        client_auth_info: ClientAuthInfo,
1489        eventid: Uuid,
1490    ) -> Result<Vec<AppLink>, OperationError> {
1491        let ct = duration_from_epoch_now();
1492        let mut idms_prox_read = self.idms.proxy_read().await?;
1493        let ident = idms_prox_read
1494            .validate_client_auth_info_to_ident(client_auth_info, ct)
1495            .map_err(|e| {
1496                error!("Invalid identity: {:?}", e);
1497                e
1498            })?;
1499
1500        idms_prox_read.list_applinks(&ident)
1502    }
1503
1504    #[instrument(
1505        level = "info",
1506        skip_all,
1507        fields(uuid = ?eventid)
1508    )]
1509    pub async fn handle_auth_valid(
1510        &self,
1511        client_auth_info: ClientAuthInfo,
1512        eventid: Uuid,
1513    ) -> Result<(), OperationError> {
1514        let ct = duration_from_epoch_now();
1515        let mut idms_prox_read = self.idms.proxy_read().await?;
1516
1517        idms_prox_read
1518            .validate_client_auth_info_to_ident(client_auth_info, ct)
1519            .map(|_| ())
1520            .map_err(|e| {
1521                error!("Invalid identity: {:?}", e);
1522                e
1523            })
1524    }
1525
1526    #[instrument(
1527        level = "info",
1528        skip_all,
1529        fields(uuid = ?eventid)
1530    )]
1531    pub async fn handle_public_jwk_get(
1533        &self,
1534        key_id: String,
1535        eventid: Uuid,
1536    ) -> Result<Jwk, OperationError> {
1537        let mut idms_prox_read = self.idms.proxy_read().await?;
1538
1539        idms_prox_read.jws_public_jwk(key_id.as_str())
1540    }
1541
1542    #[instrument(
1543        level = "info",
1544        skip_all,
1545        fields(uuid = ?eventid)
1546    )]
1547    pub async fn handle_ldaprequest(
1548        &self,
1549        eventid: Uuid,
1550        protomsg: LdapMsg,
1551        uat: Option<LdapBoundToken>,
1552        ip_addr: IpAddr,
1553    ) -> Option<LdapResponseState> {
1554        let res = match ServerOps::try_from(protomsg) {
1555            Ok(server_op) => self
1556                .ldap
1557                .do_op(&self.idms, server_op, uat, ip_addr, eventid)
1558                .await
1559                .unwrap_or_else(|e| {
1560                    error!("do_op failed -> {:?}", e);
1561                    LdapResponseState::Disconnect(DisconnectionNotice::gen(
1562                        LdapResultCode::Other,
1563                        format!("Internal Server Error {:?}", &eventid).as_str(),
1564                    ))
1565                }),
1566            Err(_) => LdapResponseState::Disconnect(DisconnectionNotice::gen(
1567                LdapResultCode::ProtocolError,
1568                format!("Invalid Request {:?}", &eventid).as_str(),
1569            )),
1570        };
1571        Some(res)
1572    }
1573
1574    pub fn domain_info_read(&self) -> DomainInfoRead {
1575        self.idms.domain_read()
1576    }
1577}