kanidmd_lib/valueset/
mod.rs

1use crate::be::dbvalue::DbValueSetV2;
2use crate::credential::{apppwd::ApplicationPassword, totp::Totp, Credential};
3use crate::prelude::*;
4use crate::repl::cid::Cid;
5use crate::schema::SchemaAttribute;
6use crate::server::keys::KeyId;
7use crate::value::{
8    Address, ApiToken, CredentialType, IntentTokenState, Oauth2Session, OauthClaimMapJoin, Session,
9};
10use compact_jwt::{crypto::JwsRs256Signer, JwsEs256Signer};
11use crypto_glue::s256::Sha256Output;
12use dyn_clone::DynClone;
13use hashbrown::HashSet;
14use kanidm_lib_crypto::x509_cert::Certificate;
15use kanidm_proto::internal::ImageValue;
16use kanidm_proto::internal::{Filter as ProtoFilter, UiHint};
17use kanidm_proto::scim_v1::JsonValue;
18use kanidm_proto::scim_v1::ScimOauth2ClaimMapJoinChar;
19use kanidm_proto::v1::OutboundMessage;
20use openssl::ec::EcKey;
21use openssl::pkey::Private;
22use openssl::pkey::Public;
23use smolset::SmolSet;
24use sshkey_attest::proto::PublicKey as SshPublicKey;
25use std::cmp::Ordering;
26use std::collections::{BTreeMap, BTreeSet};
27use time::OffsetDateTime;
28use webauthn_rs::prelude::AttestationCaList;
29use webauthn_rs::prelude::AttestedPasskey as AttestedPasskeyV4;
30use webauthn_rs::prelude::Passkey as PasskeyV4;
31
32pub use self::address::{ValueSetAddress, ValueSetEmailAddress};
33use self::apppwd::ValueSetApplicationPassword;
34pub use self::auditlogstring::{ValueSetAuditLogString, AUDIT_LOG_STRING_CAPACITY};
35pub use self::binary::{ValueSetPrivateBinary, ValueSetPublicBinary};
36pub use self::bool::ValueSetBool;
37pub use self::certificate::ValueSetCertificate;
38pub use self::cid::ValueSetCid;
39pub use self::cred::{
40    ValueSetAttestedPasskey, ValueSetCredential, ValueSetCredentialType, ValueSetIntentToken,
41    ValueSetPasskey, ValueSetWebauthnAttestationCaList,
42};
43pub use self::datetime::ValueSetDateTime;
44pub use self::eckey::ValueSetEcKeyPrivate;
45pub use self::hexstring::ValueSetHexString;
46use self::image::ValueSetImage;
47pub use self::iname::ValueSetIname;
48pub use self::index::ValueSetIndex;
49pub use self::int64::ValueSetInt64;
50pub use self::iutf8::ValueSetIutf8;
51pub use self::json::{ValueSetJson, ValueSetJsonFilter};
52pub use self::jws::{ValueSetJwsKeyEs256, ValueSetJwsKeyRs256};
53pub use self::key_internal::{KeyInternalData, ValueSetKeyInternal};
54pub use self::message::ValueSetMessage;
55pub use self::nsuniqueid::ValueSetNsUniqueId;
56pub use self::oauth::{
57    OauthClaimMapping, ValueSetOauthClaimMap, ValueSetOauthScope, ValueSetOauthScopeMap,
58};
59pub use self::restricted::ValueSetRestricted;
60pub use self::s256::ValueSetSha256;
61pub use self::secret::ValueSetSecret;
62pub use self::session::{ValueSetApiToken, ValueSetOauth2Session, ValueSetSession};
63pub use self::spn::ValueSetSpn;
64pub use self::ssh::ValueSetSshKey;
65pub use self::syntax::ValueSetSyntax;
66pub use self::totp::ValueSetTotpSecret;
67pub use self::uihint::ValueSetUiHint;
68pub use self::uint32::ValueSetUint32;
69pub use self::uint64::ValueSetUint64;
70pub use self::url::ValueSetUrl;
71pub use self::utf8::ValueSetUtf8;
72pub use self::uuid::{ValueSetRefer, ValueSetUuid};
73
74mod address;
75mod apppwd;
76mod auditlogstring;
77mod binary;
78mod bool;
79mod certificate;
80mod cid;
81mod cred;
82mod datetime;
83pub mod eckey;
84mod hexstring;
85pub mod image;
86mod iname;
87mod index;
88mod int64;
89mod iutf8;
90mod json;
91mod jws;
92mod key_internal;
93mod message;
94mod nsuniqueid;
95mod oauth;
96mod restricted;
97mod s256;
98mod secret;
99mod session;
100mod spn;
101mod ssh;
102mod syntax;
103mod totp;
104mod uihint;
105mod uint32;
106mod uint64;
107mod url;
108mod utf8;
109mod uuid;
110
111pub type ValueSet = Box<dyn ValueSetT + Send + Sync + 'static>;
112
113dyn_clone::clone_trait_object!(ValueSetT);
114
115pub trait ValueSetT: std::fmt::Debug + DynClone {
116    /// Returns whether the value was newly inserted. That is:
117    /// * If the set did not previously contain an equal value, true is returned.
118    /// * If the set already contained an equal value, false is returned, and the entry is not updated.
119    ///
120    fn insert_checked(&mut self, value: Value) -> Result<bool, OperationError>;
121
122    fn clear(&mut self);
123
124    fn remove(&mut self, pv: &PartialValue, cid: &Cid) -> bool;
125
126    fn purge(&mut self, _cid: &Cid) -> bool {
127        // Default handling is true.
128        true
129    }
130
131    fn trim(&mut self, _trim_cid: &Cid) {
132        // default to a no-op
133    }
134
135    fn contains(&self, pv: &PartialValue) -> bool;
136
137    fn substring(&self, _pv: &crate::value::PartialValue) -> bool {
138        false
139    }
140
141    fn startswith(&self, _pv: &PartialValue) -> bool {
142        false
143    }
144
145    fn endswith(&self, _pv: &PartialValue) -> bool {
146        false
147    }
148
149    fn lessthan(&self, _pv: &crate::value::PartialValue) -> bool {
150        false
151    }
152
153    fn len(&self) -> usize;
154
155    fn generate_idx_eq_keys(&self) -> Vec<String> {
156        Vec::with_capacity(0)
157    }
158
159    fn generate_idx_sub_keys(&self) -> Vec<String> {
160        Vec::with_capacity(0)
161    }
162
163    fn generate_idx_ord_keys(&self) -> Vec<String> {
164        Vec::with_capacity(0)
165    }
166
167    fn syntax(&self) -> SyntaxType;
168
169    fn validate(&self, schema_attr: &SchemaAttribute) -> bool;
170
171    fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_>;
172
173    fn to_scim_value(&self) -> Option<ScimResolveStatus>;
174
175    fn to_db_valueset_v2(&self) -> DbValueSetV2;
176
177    fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = PartialValue> + '_>;
178
179    fn to_value_iter(&self) -> Box<dyn Iterator<Item = Value> + '_>;
180
181    fn equal(&self, other: &ValueSet) -> bool;
182
183    fn cmp(&self, _other: &ValueSet) -> Ordering {
184        // IMPORTANT - in the case we attempt to compare the ordering of two value sets
185        // that are different syntaxs or types, the CORRECT and reliable thing to do is
186        // report them as equal such that any sorting function won't rearrange the values.
187        error!("cmp should not be called on {:?}", self.syntax());
188        debug_assert!(false);
189        Ordering::Equal
190    }
191
192    fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError>;
193
194    fn is_empty(&self) -> bool {
195        self.len() == 0
196    }
197
198    fn migrate_iutf8_iname(&self) -> Result<Option<ValueSet>, OperationError> {
199        debug_assert!(false);
200        Ok(None)
201    }
202
203    fn get_ssh_tag(&self, _tag: &str) -> Option<&SshPublicKey> {
204        None
205    }
206
207    fn as_ref_uuid_iter(&self) -> Option<Box<dyn Iterator<Item = Uuid> + '_>> {
208        None
209    }
210
211    fn as_utf8_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
212        error!("as_utf8_iter should not be called on {:?}", self.syntax());
213        debug_assert!(false);
214        None
215    }
216
217    fn as_iutf8_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
218        error!("as_iutf8_iter should not be called on {:?}", self.syntax());
219        debug_assert!(false);
220        None
221    }
222
223    fn as_iname_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
224        error!("as_iname_iter should not be called on {:?}", self.syntax());
225        debug_assert!(false);
226        None
227    }
228
229    fn as_indextype_iter(&self) -> Option<Box<dyn Iterator<Item = IndexType> + '_>> {
230        error!(
231            "as_indextype_set should not be called on {:?}",
232            self.syntax()
233        );
234        None
235    }
236
237    fn as_restricted_string_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
238        error!(
239            "as_restricted_string_iter should not be called on {:?}",
240            self.syntax()
241        );
242        None
243    }
244
245    fn as_oauthscope_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
246        error!(
247            "as_oauthscope_iter should not be called on {:?}",
248            self.syntax()
249        );
250        None
251    }
252
253    fn as_sshpubkey_string_iter(&self) -> Option<Box<dyn Iterator<Item = String> + '_>> {
254        None
255    }
256
257    fn as_email_str_iter(&self) -> Option<Box<dyn Iterator<Item = &str> + '_>> {
258        None
259    }
260
261    fn as_utf8_set(&self) -> Option<&BTreeSet<String>> {
262        debug_assert!(false);
263        None
264    }
265
266    fn as_iutf8_set(&self) -> Option<&BTreeSet<String>> {
267        debug_assert!(false);
268        None
269    }
270
271    fn as_iname_set(&self) -> Option<&BTreeSet<String>> {
272        debug_assert!(false);
273        None
274    }
275
276    fn as_uuid_set(&self) -> Option<&SmolSet<[Uuid; 1]>> {
277        None
278    }
279
280    fn as_refer_set(&self) -> Option<&BTreeSet<Uuid>> {
281        None
282    }
283
284    fn as_refer_set_mut(&mut self) -> Option<&mut BTreeSet<Uuid>> {
285        debug_assert!(false);
286        None
287    }
288
289    fn as_bool_set(&self) -> Option<&SmolSet<[bool; 1]>> {
290        debug_assert!(false);
291        None
292    }
293
294    fn as_uint32_set(&self) -> Option<&SmolSet<[u32; 1]>> {
295        debug_assert!(false);
296        None
297    }
298
299    fn as_int64_set(&self) -> Option<&SmolSet<[i64; 1]>> {
300        debug_assert!(false);
301        None
302    }
303
304    fn as_uint64_set(&self) -> Option<&SmolSet<[u64; 1]>> {
305        debug_assert!(false);
306        None
307    }
308
309    fn as_syntax_set(&self) -> Option<&SmolSet<[SyntaxType; 1]>> {
310        debug_assert!(false);
311        None
312    }
313
314    fn as_index_set(&self) -> Option<&SmolSet<[IndexType; 3]>> {
315        debug_assert!(false);
316        None
317    }
318
319    fn as_secret_set(&self) -> Option<&SmolSet<[String; 1]>> {
320        debug_assert!(false);
321        None
322    }
323
324    fn as_restricted_string_set(&self) -> Option<&BTreeSet<String>> {
325        debug_assert!(false);
326        None
327    }
328
329    fn as_spn_set(&self) -> Option<&SmolSet<[(String, String); 1]>> {
330        debug_assert!(false);
331        None
332    }
333
334    fn as_cid_set(&self) -> Option<&SmolSet<[Cid; 1]>> {
335        debug_assert!(false);
336        None
337    }
338
339    fn as_json_filter_set(&self) -> Option<&SmolSet<[ProtoFilter; 1]>> {
340        debug_assert!(false);
341        None
342    }
343
344    fn as_nsuniqueid_set(&self) -> Option<&SmolSet<[String; 1]>> {
345        debug_assert!(false);
346        None
347    }
348
349    fn as_url_set(&self) -> Option<&SmolSet<[Url; 1]>> {
350        debug_assert!(false);
351        None
352    }
353
354    fn as_datetime_set(&self) -> Option<&SmolSet<[OffsetDateTime; 1]>> {
355        debug_assert!(false);
356        None
357    }
358
359    fn as_private_binary_set(&self) -> Option<&SmolSet<[Vec<u8>; 1]>> {
360        debug_assert!(false);
361        None
362    }
363
364    fn as_oauthscope_set(&self) -> Option<&BTreeSet<String>> {
365        debug_assert!(false);
366        None
367    }
368
369    fn as_address_set(&self) -> Option<&SmolSet<[Address; 1]>> {
370        debug_assert!(false);
371        None
372    }
373
374    fn as_credential_map(&self) -> Option<&BTreeMap<String, Credential>> {
375        debug_assert!(false);
376        None
377    }
378
379    fn as_totp_map(&self) -> Option<&BTreeMap<String, Totp>> {
380        debug_assert!(false);
381        None
382    }
383
384    fn as_emailaddress_set(&self) -> Option<(&String, &BTreeSet<String>)> {
385        debug_assert!(false);
386        None
387    }
388
389    fn as_sshkey_map(&self) -> Option<&BTreeMap<String, SshPublicKey>> {
390        None
391    }
392
393    fn as_oauthscopemap(&self) -> Option<&BTreeMap<Uuid, BTreeSet<String>>> {
394        /*
395        error!(
396            "as_oauthscopemap should not be called on {:?}",
397            self.syntax()
398        );
399        */
400        None
401    }
402
403    fn as_publicbinary_map(&self) -> Option<&BTreeMap<String, Vec<u8>>> {
404        debug_assert!(false);
405        None
406    }
407
408    fn as_intenttoken_map(&self) -> Option<&BTreeMap<String, IntentTokenState>> {
409        debug_assert!(false);
410        None
411    }
412
413    fn as_passkey_map(&self) -> Option<&BTreeMap<Uuid, (String, PasskeyV4)>> {
414        debug_assert!(false);
415        None
416    }
417
418    fn as_attestedpasskey_map(&self) -> Option<&BTreeMap<Uuid, (String, AttestedPasskeyV4)>> {
419        debug_assert!(false);
420        None
421    }
422
423    fn as_webauthn_attestation_ca_list(&self) -> Option<&AttestationCaList> {
424        debug_assert!(false);
425        None
426    }
427
428    fn as_oauthclaim_map(&self) -> Option<&BTreeMap<String, OauthClaimMapping>> {
429        None
430    }
431
432    fn as_key_internal_map(&self) -> Option<&BTreeMap<KeyId, KeyInternalData>> {
433        debug_assert!(false);
434        None
435    }
436
437    fn as_hexstring_set(&self) -> Option<&BTreeSet<String>> {
438        debug_assert!(false);
439        None
440    }
441
442    fn as_application_password_map(&self) -> Option<&BTreeMap<Uuid, Vec<ApplicationPassword>>> {
443        debug_assert!(false);
444        None
445    }
446
447    fn to_value_single(&self) -> Option<Value> {
448        if self.len() != 1 {
449            None
450        } else {
451            self.to_value_iter().take(1).next()
452        }
453    }
454
455    fn to_proto_string_single(&self) -> Option<String> {
456        if self.len() != 1 {
457            None
458        } else {
459            self.to_proto_string_clone_iter().take(1).next()
460        }
461    }
462
463    fn to_uuid_single(&self) -> Option<Uuid> {
464        error!("to_uuid_single should not be called on {:?}", self.syntax());
465        None
466    }
467
468    fn to_cid_single(&self) -> Option<Cid> {
469        error!("to_cid_single should not be called on {:?}", self.syntax());
470        None
471    }
472
473    fn to_refer_single(&self) -> Option<Uuid> {
474        error!(
475            "to_refer_single should not be called on {:?}",
476            self.syntax()
477        );
478        debug_assert!(false);
479        None
480    }
481
482    fn to_bool_single(&self) -> Option<bool> {
483        error!("to_bool_single should not be called on {:?}", self.syntax());
484        None
485    }
486
487    fn to_uint32_single(&self) -> Option<u32> {
488        error!(
489            "to_uint32_single should not be called on {:?}",
490            self.syntax()
491        );
492        debug_assert!(false);
493        None
494    }
495
496    fn to_int64_single(&self) -> Option<i64> {
497        error!(
498            "to_int64_single should not be called on {:?}",
499            self.syntax()
500        );
501        debug_assert!(false);
502        None
503    }
504
505    fn to_uint64_single(&self) -> Option<u64> {
506        error!(
507            "to_uint64_single should not be called on {:?}",
508            self.syntax()
509        );
510        debug_assert!(false);
511        None
512    }
513
514    fn to_syntaxtype_single(&self) -> Option<SyntaxType> {
515        error!(
516            "to_syntaxtype_single should not be called on {:?}",
517            self.syntax()
518        );
519        None
520    }
521
522    fn to_credential_single(&self) -> Option<&Credential> {
523        error!(
524            "to_credential_single should not be called on {:?}",
525            self.syntax()
526        );
527        debug_assert!(false);
528        None
529    }
530
531    fn to_secret_single(&self) -> Option<&str> {
532        error!(
533            "to_secret_single should not be called on {:?}",
534            self.syntax()
535        );
536        debug_assert!(false);
537        None
538    }
539
540    fn to_restricted_string_single(&self) -> Option<&str> {
541        error!(
542            "to_restricted_string_single should not be called on {:?}",
543            self.syntax()
544        );
545        debug_assert!(false);
546        None
547    }
548
549    fn to_utf8_single(&self) -> Option<&str> {
550        error!("to_utf8_single should not be called on {:?}", self.syntax());
551        debug_assert!(false);
552        None
553    }
554
555    fn to_iutf8_single(&self) -> Option<&str> {
556        error!(
557            "to_iutf8_single should not be called on {:?}",
558            self.syntax()
559        );
560        debug_assert!(false);
561        None
562    }
563
564    fn to_iname_single(&self) -> Option<&str> {
565        error!(
566            "to_iname_single should not be called on {:?}",
567            self.syntax()
568        );
569        debug_assert!(false);
570        None
571    }
572
573    fn to_datetime_single(&self) -> Option<OffsetDateTime> {
574        error!(
575            "to_datetime_single should not be called on {:?}",
576            self.syntax()
577        );
578        debug_assert!(false);
579        None
580    }
581
582    fn to_url_single(&self) -> Option<&Url> {
583        error!("to_url_single should not be called on {:?}", self.syntax());
584        debug_assert!(false);
585        None
586    }
587
588    fn to_json_filter_single(&self) -> Option<&ProtoFilter> {
589        error!(
590            "to_json_filter_single should not be called on {:?}",
591            self.syntax()
592        );
593        // debug_assert!(false);
594        None
595    }
596
597    fn to_email_address_primary_str(&self) -> Option<&str> {
598        debug_assert!(false);
599        None
600    }
601
602    fn to_private_binary_single(&self) -> Option<&[u8]> {
603        debug_assert!(false);
604        None
605    }
606
607    fn to_passkey_single(&self) -> Option<&PasskeyV4> {
608        debug_assert!(false);
609        None
610    }
611
612    fn as_session_map(&self) -> Option<&BTreeMap<Uuid, Session>> {
613        debug_assert!(false);
614        None
615    }
616
617    fn as_apitoken_map(&self) -> Option<&BTreeMap<Uuid, ApiToken>> {
618        debug_assert!(false);
619        None
620    }
621
622    fn as_oauth2session_map(&self) -> Option<&BTreeMap<Uuid, Oauth2Session>> {
623        debug_assert!(false);
624        None
625    }
626
627    fn to_jws_key_es256_single(&self) -> Option<&JwsEs256Signer> {
628        debug_assert!(false);
629        None
630    }
631
632    fn to_eckey_private_single(&self) -> Option<&EcKey<Private>> {
633        debug_assert!(false);
634        None
635    }
636
637    fn to_eckey_public_single(&self) -> Option<&EcKey<Public>> {
638        debug_assert!(false);
639        None
640    }
641
642    fn as_jws_key_es256_set(&self) -> Option<&HashSet<JwsEs256Signer>> {
643        debug_assert!(false);
644        None
645    }
646
647    fn to_jws_key_rs256_single(&self) -> Option<&JwsRs256Signer> {
648        debug_assert!(false);
649        None
650    }
651
652    fn as_jws_key_rs256_set(&self) -> Option<&HashSet<JwsRs256Signer>> {
653        debug_assert!(false);
654        None
655    }
656
657    fn as_uihint_set(&self) -> Option<&BTreeSet<UiHint>> {
658        debug_assert!(false);
659        None
660    }
661
662    fn as_uihint_iter(&self) -> Option<Box<dyn Iterator<Item = UiHint> + '_>> {
663        debug_assert!(false);
664        None
665    }
666
667    fn as_audit_log_string(&self) -> Option<&BTreeMap<Cid, String>> {
668        debug_assert!(false);
669        None
670    }
671
672    fn as_ec_key_private(&self) -> Option<&EcKey<Private>> {
673        debug_assert!(false);
674        None
675    }
676
677    fn as_imageset(&self) -> Option<&HashSet<ImageValue>> {
678        debug_assert!(false);
679        None
680    }
681
682    fn to_credentialtype_single(&self) -> Option<CredentialType> {
683        debug_assert!(false);
684        None
685    }
686
687    fn as_credentialtype_set(&self) -> Option<&SmolSet<[CredentialType; 1]>> {
688        debug_assert!(false);
689        None
690    }
691
692    fn to_certificate_single(&self) -> Option<&Certificate> {
693        debug_assert!(false);
694        None
695    }
696
697    fn as_certificate_set(&self) -> Option<&BTreeMap<Sha256Output, Box<Certificate>>> {
698        debug_assert!(false);
699        None
700    }
701
702    fn as_json_object(&self) -> Option<&JsonValue> {
703        debug_assert!(false);
704        None
705    }
706
707    fn as_message(&self) -> Option<&OutboundMessage> {
708        debug_assert!(false);
709        None
710    }
711
712    fn as_s256_set(&self) -> Option<&BTreeSet<Sha256Output>> {
713        debug_assert!(false);
714        None
715    }
716
717    fn as_s256_set_mut(&mut self) -> Option<&mut BTreeSet<Sha256Output>> {
718        debug_assert!(false);
719        None
720    }
721
722    fn repl_merge_valueset(
723        &self,
724        _older: &ValueSet,
725        _trim_cid: &Cid, // schema_attr: &SchemaAttribute
726    ) -> Option<ValueSet> {
727        // Self is the "latest" content. Older contains the earlier
728        // state of the attribute.
729        //
730        // In most cases we don't actually need a merge strategy. We just need the
731        // newer state of the attribute.
732        //
733        // However when we have a merge strategy that is required we return
734        // Some(new_state) if and only if merges were applied that need to be added
735        // to the change state.
736        //
737        // If no merge was required, we just return None.
738        //
739        // Examples where we need merging is session states. This has an internal
740        // attribute state machine that works similarly to tombstones to ensure that
741        // after a certain period that attributes are cleaned up.
742        None
743    }
744}
745
746pub trait ValueSetScimPut {
747    fn from_scim_json_put(value: JsonValue) -> Result<ValueSetResolveStatus, OperationError>;
748}
749
750impl PartialEq for ValueSet {
751    fn eq(&self, other: &ValueSet) -> bool {
752        self.equal(other)
753    }
754}
755
756pub struct UnresolvedScimValueOauth2ClaimMap {
757    pub group_uuid: Uuid,
758    pub claim: String,
759    pub join_char: ScimOauth2ClaimMapJoinChar,
760    pub values: BTreeSet<String>,
761}
762
763pub struct UnresolvedScimValueOauth2ScopeMap {
764    pub group_uuid: Uuid,
765    pub scopes: BTreeSet<String>,
766}
767
768pub enum ScimValueIntermediate {
769    References(Vec<Uuid>),
770    Oauth2ClaimMap(Vec<UnresolvedScimValueOauth2ClaimMap>),
771    Oauth2ScopeMap(Vec<UnresolvedScimValueOauth2ScopeMap>),
772}
773
774pub enum ScimResolveStatus {
775    Resolved(ScimValueKanidm),
776    NeedsResolution(ScimValueIntermediate),
777}
778
779impl<T> From<T> for ScimResolveStatus
780where
781    T: Into<ScimValueKanidm>,
782{
783    fn from(v: T) -> Self {
784        Self::Resolved(v.into())
785    }
786}
787
788#[cfg(test)]
789impl ScimResolveStatus {
790    pub fn assume_resolved(self) -> ScimValueKanidm {
791        match self {
792            ScimResolveStatus::Resolved(v) => v,
793            ScimResolveStatus::NeedsResolution(_) => {
794                panic!("assume_resolved called on NeedsResolution")
795            }
796        }
797    }
798
799    pub fn assume_unresolved(self) -> ScimValueIntermediate {
800        match self {
801            ScimResolveStatus::Resolved(_) => panic!("assume_unresolved called on Resolved"),
802            ScimResolveStatus::NeedsResolution(svi) => svi,
803        }
804    }
805}
806
807pub enum ValueSetResolveStatus {
808    Resolved(ValueSet),
809    NeedsResolution(ValueSetIntermediate),
810}
811
812#[cfg(test)]
813impl ValueSetResolveStatus {
814    pub fn assume_resolved(self) -> ValueSet {
815        match self {
816            ValueSetResolveStatus::Resolved(v) => v,
817            ValueSetResolveStatus::NeedsResolution(_) => {
818                panic!("assume_resolved called on NeedsResolution")
819            }
820        }
821    }
822
823    pub fn assume_unresolved(self) -> ValueSetIntermediate {
824        match self {
825            ValueSetResolveStatus::Resolved(_) => panic!("assume_unresolved called on Resolved"),
826            ValueSetResolveStatus::NeedsResolution(svi) => svi,
827        }
828    }
829}
830
831pub enum ValueSetIntermediate {
832    References {
833        resolved: BTreeSet<Uuid>,
834        unresolved: Vec<String>,
835    },
836    Oauth2ClaimMap {
837        resolved: Vec<ResolvedValueSetOauth2ClaimMap>,
838        unresolved: Vec<UnresolvedValueSetOauth2ClaimMap>,
839    },
840    Oauth2ScopeMap {
841        resolved: Vec<ResolvedValueSetOauth2ScopeMap>,
842        unresolved: Vec<UnresolvedValueSetOauth2ScopeMap>,
843    },
844}
845
846pub struct UnresolvedValueSetOauth2ClaimMap {
847    pub group_name: String,
848    pub claim: String,
849    pub join_char: OauthClaimMapJoin,
850    pub claim_values: BTreeSet<String>,
851}
852
853pub struct ResolvedValueSetOauth2ClaimMap {
854    pub group_uuid: Uuid,
855    pub claim: String,
856    pub join_char: OauthClaimMapJoin,
857    pub claim_values: BTreeSet<String>,
858}
859
860pub struct UnresolvedValueSetOauth2ScopeMap {
861    pub group_name: String,
862    pub scopes: BTreeSet<String>,
863}
864
865pub struct ResolvedValueSetOauth2ScopeMap {
866    pub group_uuid: Uuid,
867    pub scopes: BTreeSet<String>,
868}
869
870pub fn uuid_to_proto_string(u: Uuid) -> String {
871    u.as_hyphenated().to_string()
872}
873
874pub fn from_result_value_iter(
875    mut iter: impl Iterator<Item = Result<Value, OperationError>>,
876) -> Result<ValueSet, OperationError> {
877    let Some(init) = iter.next() else {
878        trace!("Empty value iterator");
879        return Err(OperationError::InvalidValueState);
880    };
881
882    let init = init?;
883
884    let mut vs: ValueSet = match init {
885        Value::Utf8(s) => ValueSetUtf8::new(s),
886        Value::Iutf8(s) => ValueSetIutf8::new(&s),
887        Value::Iname(s) => ValueSetIname::new(&s),
888        Value::Uuid(u) => ValueSetUuid::new(u),
889        Value::Refer(u) => ValueSetRefer::new(u),
890        Value::Bool(u) => ValueSetBool::new(u),
891        Value::Uint32(u) => ValueSetUint32::new(u),
892        Value::Int64(u) => ValueSetInt64::new(u),
893        Value::Uint64(u) => ValueSetUint64::new(u),
894        Value::Syntax(u) => ValueSetSyntax::new(u),
895        Value::Index(u) => ValueSetIndex::new(u),
896        Value::SecretValue(u) => ValueSetSecret::new(u),
897        Value::RestrictedString(u) => ValueSetRestricted::new(u),
898        Value::Spn(n, d) => ValueSetSpn::new((n, d)),
899        Value::Cid(u) => ValueSetCid::new(u),
900        Value::JsonFilt(u) => ValueSetJsonFilter::new(u),
901        Value::Nsuniqueid(u) => ValueSetNsUniqueId::new(u),
902        Value::Url(u) => ValueSetUrl::new(u),
903        Value::DateTime(u) => ValueSetDateTime::new(u),
904        Value::PrivateBinary(u) => ValueSetPrivateBinary::new(u),
905        Value::OauthScope(u) => ValueSetOauthScope::new(u),
906        Value::Address(u) => ValueSetAddress::new(u),
907        Value::Cred(t, c) => ValueSetCredential::new(t, c),
908        Value::SshKey(t, k) => ValueSetSshKey::new(t, k),
909        Value::OauthScopeMap(u, m) => ValueSetOauthScopeMap::new(u, m),
910        Value::PublicBinary(t, b) => ValueSetPublicBinary::new(t, b),
911        Value::IntentToken(u, s) => ValueSetIntentToken::new(u, s),
912        Value::EmailAddress(a, _) => ValueSetEmailAddress::new(a),
913        Value::UiHint(u) => ValueSetUiHint::new(u),
914        Value::AuditLogString(c, s) => ValueSetAuditLogString::new((c, s)),
915        Value::EcKeyPrivate(k) => ValueSetEcKeyPrivate::new(&k),
916        Value::Image(imagevalue) => image::ValueSetImage::new(imagevalue),
917        Value::CredentialType(c) => ValueSetCredentialType::new(c),
918        Value::Certificate(c) => ValueSetCertificate::new(c)?,
919        Value::WebauthnAttestationCaList(_)
920        | Value::PhoneNumber(_, _)
921        | Value::ApplicationPassword(_)
922        | Value::Passkey(_, _, _)
923        | Value::AttestedPasskey(_, _, _)
924        | Value::TotpSecret(_, _)
925        | Value::Session(_, _)
926        | Value::ApiToken(_, _)
927        | Value::Oauth2Session(_, _)
928        | Value::OauthClaimMap(_, _)
929        | Value::OauthClaimValue(_, _, _)
930        | Value::JwsKeyEs256(_)
931        | Value::JwsKeyRs256(_)
932        | Value::HexString(_)
933        | Value::Json(_)
934        | Value::Sha256(_)
935        | Value::KeyInternal { .. } => {
936            debug_assert!(false);
937            return Err(OperationError::InvalidValueState);
938        }
939    };
940
941    for maybe_v in iter {
942        let v = maybe_v?;
943        // Need to error if wrong type (but shouldn't be due to the way qs works)
944        vs.insert_checked(v)?;
945    }
946    Ok(vs)
947}
948
949pub fn from_value_iter(mut iter: impl Iterator<Item = Value>) -> Result<ValueSet, OperationError> {
950    let Some(init) = iter.next() else {
951        trace!("Empty value iterator");
952        return Err(OperationError::InvalidValueState);
953    };
954
955    let mut vs: ValueSet = match init {
956        Value::Utf8(s) => ValueSetUtf8::new(s),
957        Value::Iutf8(s) => ValueSetIutf8::new(&s),
958        Value::Iname(s) => ValueSetIname::new(&s),
959        Value::Uuid(u) => ValueSetUuid::new(u),
960        Value::Refer(u) => ValueSetRefer::new(u),
961        Value::Bool(u) => ValueSetBool::new(u),
962        Value::Uint32(u) => ValueSetUint32::new(u),
963        Value::Int64(u) => ValueSetInt64::new(u),
964        Value::Uint64(u) => ValueSetUint64::new(u),
965        Value::Syntax(u) => ValueSetSyntax::new(u),
966        Value::Index(u) => ValueSetIndex::new(u),
967        Value::SecretValue(u) => ValueSetSecret::new(u),
968        Value::RestrictedString(u) => ValueSetRestricted::new(u),
969        Value::Spn(n, d) => ValueSetSpn::new((n, d)),
970        Value::Cid(u) => ValueSetCid::new(u),
971        Value::JsonFilt(u) => ValueSetJsonFilter::new(u),
972        Value::Nsuniqueid(u) => ValueSetNsUniqueId::new(u),
973        Value::Url(u) => ValueSetUrl::new(u),
974        Value::DateTime(u) => ValueSetDateTime::new(u),
975        Value::PrivateBinary(u) => ValueSetPrivateBinary::new(u),
976        Value::OauthScope(u) => ValueSetOauthScope::new(u),
977        Value::Address(u) => ValueSetAddress::new(u),
978        Value::Cred(t, c) => ValueSetCredential::new(t, c),
979        Value::SshKey(t, k) => ValueSetSshKey::new(t, k),
980        Value::OauthScopeMap(u, m) => ValueSetOauthScopeMap::new(u, m),
981        Value::PublicBinary(t, b) => ValueSetPublicBinary::new(t, b),
982        Value::IntentToken(u, s) => ValueSetIntentToken::new(u, s),
983        Value::EmailAddress(a, _) => ValueSetEmailAddress::new(a),
984        Value::Passkey(u, t, k) => ValueSetPasskey::new(u, t, k),
985        Value::AttestedPasskey(u, t, k) => ValueSetAttestedPasskey::new(u, t, k),
986        Value::JwsKeyEs256(k) => ValueSetJwsKeyEs256::new(k),
987        Value::JwsKeyRs256(k) => ValueSetJwsKeyRs256::new(k),
988        Value::Session(u, m) => ValueSetSession::new(u, m),
989        Value::ApiToken(u, m) => ValueSetApiToken::new(u, m),
990        Value::Oauth2Session(u, m) => ValueSetOauth2Session::new(u, m),
991        Value::UiHint(u) => ValueSetUiHint::new(u),
992        Value::TotpSecret(l, t) => ValueSetTotpSecret::new(l, t),
993        Value::AuditLogString(c, s) => ValueSetAuditLogString::new((c, s)),
994        Value::EcKeyPrivate(k) => ValueSetEcKeyPrivate::new(&k),
995        Value::Image(imagevalue) => image::ValueSetImage::new(imagevalue),
996        Value::CredentialType(c) => ValueSetCredentialType::new(c),
997        Value::WebauthnAttestationCaList(ca_list) => {
998            ValueSetWebauthnAttestationCaList::new(ca_list)
999        }
1000        Value::OauthClaimMap(name, join) => ValueSetOauthClaimMap::new(name, join),
1001        Value::OauthClaimValue(name, group, claims) => {
1002            ValueSetOauthClaimMap::new_value(name, group, claims)
1003        }
1004        Value::HexString(s) => ValueSetHexString::new(s),
1005
1006        Value::KeyInternal {
1007            id,
1008            usage,
1009            valid_from,
1010            status,
1011            status_cid,
1012            der,
1013        } => ValueSetKeyInternal::new(id, usage, valid_from, status, status_cid, der),
1014        Value::Certificate(certificate) => ValueSetCertificate::new(certificate)?,
1015        Value::PhoneNumber(_, _) => {
1016            debug_assert!(false);
1017            return Err(OperationError::InvalidValueState);
1018        }
1019        Value::ApplicationPassword(ap) => ValueSetApplicationPassword::new(ap),
1020        Value::Sha256(_) => {
1021            debug_assert!(false);
1022            return Err(OperationError::InvalidValueState);
1023        }
1024        Value::Json(_) => {
1025            debug_assert!(false);
1026            return Err(OperationError::InvalidValueState);
1027        }
1028    };
1029
1030    for v in iter {
1031        vs.insert_checked(v)?;
1032    }
1033    Ok(vs)
1034}
1035
1036pub fn from_db_valueset_v2(dbvs: DbValueSetV2) -> Result<ValueSet, OperationError> {
1037    match dbvs {
1038        DbValueSetV2::Utf8(set) => ValueSetUtf8::from_dbvs2(set),
1039        DbValueSetV2::Iutf8(set) => ValueSetIutf8::from_dbvs2(set),
1040        DbValueSetV2::Iname(set) => ValueSetIname::from_dbvs2(set),
1041        DbValueSetV2::Uuid(set) => ValueSetUuid::from_dbvs2(set),
1042        DbValueSetV2::Reference(set) => ValueSetRefer::from_dbvs2(set),
1043        DbValueSetV2::Bool(set) => ValueSetBool::from_dbvs2(set),
1044        DbValueSetV2::Uint32(set) => ValueSetUint32::from_dbvs2(set),
1045        DbValueSetV2::Int64(set) => ValueSetInt64::from_dbvs2(set),
1046        DbValueSetV2::Uint64(set) => ValueSetUint64::from_dbvs2(set),
1047        DbValueSetV2::SyntaxType(set) => ValueSetSyntax::from_dbvs2(set),
1048        DbValueSetV2::IndexType(set) => ValueSetIndex::from_dbvs2(set),
1049        DbValueSetV2::SecretValue(set) => ValueSetSecret::from_dbvs2(set),
1050        DbValueSetV2::RestrictedString(set) => ValueSetRestricted::from_dbvs2(set),
1051        DbValueSetV2::Spn(set) => ValueSetSpn::from_dbvs2(set),
1052        DbValueSetV2::Cid(set) => ValueSetCid::from_dbvs2(set),
1053        DbValueSetV2::JsonFilter(set) => ValueSetJsonFilter::from_dbvs2(&set),
1054        DbValueSetV2::NsUniqueId(set) => ValueSetNsUniqueId::from_dbvs2(set),
1055        DbValueSetV2::Url(set) => ValueSetUrl::from_dbvs2(set),
1056        DbValueSetV2::DateTime(set) => ValueSetDateTime::from_dbvs2(set),
1057        DbValueSetV2::PrivateBinary(set) => ValueSetPrivateBinary::from_dbvs2(set),
1058        DbValueSetV2::OauthScope(set) => ValueSetOauthScope::from_dbvs2(set),
1059        DbValueSetV2::Address(set) => ValueSetAddress::from_dbvs2(set),
1060        DbValueSetV2::Credential(set) => ValueSetCredential::from_dbvs2(set),
1061        DbValueSetV2::SshKey(set) => ValueSetSshKey::from_dbvs2(set),
1062        DbValueSetV2::OauthScopeMap(set) => ValueSetOauthScopeMap::from_dbvs2(set),
1063        DbValueSetV2::PublicBinary(set) => ValueSetPublicBinary::from_dbvs2(set),
1064        DbValueSetV2::IntentToken(set) => ValueSetIntentToken::from_dbvs2(set),
1065        DbValueSetV2::EmailAddress(primary, set) => ValueSetEmailAddress::from_dbvs2(primary, set),
1066        DbValueSetV2::Passkey(set) => ValueSetPasskey::from_dbvs2(set),
1067        DbValueSetV2::AttestedPasskey(set) => ValueSetAttestedPasskey::from_dbvs2(set),
1068        DbValueSetV2::Session(set) => ValueSetSession::from_dbvs2(&set),
1069        DbValueSetV2::ApiToken(set) => ValueSetApiToken::from_dbvs2(set),
1070        DbValueSetV2::Oauth2Session(set) => ValueSetOauth2Session::from_dbvs2(set),
1071        DbValueSetV2::JwsKeyEs256(set) => ValueSetJwsKeyEs256::from_dbvs2(&set),
1072        DbValueSetV2::JwsKeyRs256(set) => ValueSetJwsKeyEs256::from_dbvs2(&set),
1073        DbValueSetV2::UiHint(set) => ValueSetUiHint::from_dbvs2(set),
1074        DbValueSetV2::TotpSecret(set) => ValueSetTotpSecret::from_dbvs2(set),
1075        DbValueSetV2::AuditLogString(set) => ValueSetAuditLogString::from_dbvs2(set),
1076        DbValueSetV2::EcKeyPrivate(key) => ValueSetEcKeyPrivate::from_dbvs2(&key),
1077        DbValueSetV2::PhoneNumber(_, _) | DbValueSetV2::TrustedDeviceEnrollment(_) => {
1078            debug_assert!(false);
1079            Err(OperationError::InvalidValueState)
1080        }
1081        DbValueSetV2::Image(set) => ValueSetImage::from_dbvs2(&set),
1082        DbValueSetV2::CredentialType(set) => ValueSetCredentialType::from_dbvs2(set),
1083        DbValueSetV2::WebauthnAttestationCaList { ca_list } => {
1084            ValueSetWebauthnAttestationCaList::from_dbvs2(ca_list)
1085        }
1086        DbValueSetV2::OauthClaimMap(set) => ValueSetOauthClaimMap::from_dbvs2(set),
1087        DbValueSetV2::KeyInternal(set) => ValueSetKeyInternal::from_dbvs2(set),
1088        DbValueSetV2::HexString(set) => ValueSetHexString::from_dbvs2(set),
1089        DbValueSetV2::Certificate(set) => ValueSetCertificate::from_dbvs2(set),
1090        DbValueSetV2::ApplicationPassword(set) => ValueSetApplicationPassword::from_dbvs2(set),
1091        DbValueSetV2::Json(object) => Ok(ValueSetJson::new(object)),
1092        DbValueSetV2::Sha256(set) => ValueSetSha256::from_dbvs2(set),
1093        DbValueSetV2::Message(object) => Ok(ValueSetMessage::new(object)),
1094    }
1095}
1096
1097#[cfg(test)]
1098pub(crate) fn scim_json_reflexive(vs: &ValueSet, data: &str) {
1099    let scim_value = vs.to_scim_value().unwrap().assume_resolved();
1100
1101    let strout = serde_json::to_string_pretty(&scim_value).unwrap();
1102    eprintln!("{strout}");
1103
1104    let json_value: serde_json::Value = serde_json::to_value(&scim_value).unwrap();
1105
1106    eprintln!("{data}");
1107    let expect: serde_json::Value = serde_json::from_str(data).unwrap();
1108
1109    assert_eq!(json_value, expect);
1110}
1111
1112#[cfg(test)]
1113pub(crate) fn scim_json_reflexive_unresolved(
1114    write_txn: &mut QueryServerWriteTransaction,
1115    vs: &ValueSet,
1116    data: &str,
1117) {
1118    let scim_int_value = vs.to_scim_value().unwrap().assume_unresolved();
1119    let scim_value = write_txn.resolve_scim_interim(scim_int_value).unwrap();
1120
1121    let strout = serde_json::to_string_pretty(&scim_value).expect("Failed to serialize");
1122    eprintln!("{strout}");
1123
1124    let json_value: serde_json::Value =
1125        serde_json::to_value(&scim_value).expect("Failed to convert to JSON");
1126
1127    let expect: serde_json::Value =
1128        serde_json::from_str(data).expect("Failed to parse expected JSON");
1129
1130    assert_eq!(json_value, expect);
1131}
1132
1133#[cfg(test)]
1134pub(crate) fn scim_json_put_reflexive<T: ValueSetScimPut>(
1135    expect_vs: &ValueSet,
1136    additional_tests: &[(JsonValue, ValueSet)],
1137) {
1138    let scim_value = expect_vs.to_scim_value().unwrap().assume_resolved();
1139
1140    let strout = serde_json::to_string_pretty(&scim_value).unwrap();
1141    eprintln!("{strout}");
1142
1143    let generic = serde_json::to_value(scim_value).unwrap();
1144    // Check that we can turn back into a vs from the generic version.
1145    let vs = T::from_scim_json_put(generic).unwrap().assume_resolved();
1146    assert_eq!(&vs, expect_vs);
1147
1148    // For each additional check, assert they work as expected.
1149    for (jv, expect_vs) in additional_tests {
1150        let vs = T::from_scim_json_put(jv.clone()).unwrap().assume_resolved();
1151        assert_eq!(&vs, expect_vs);
1152    }
1153}
1154
1155#[cfg(test)]
1156pub(crate) fn scim_json_put_reflexive_unresolved<T: ValueSetScimPut>(
1157    write_txn: &mut QueryServerWriteTransaction,
1158    expect_vs: &ValueSet,
1159    additional_tests: &[(JsonValue, ValueSet)],
1160) {
1161    let scim_int_value = expect_vs.to_scim_value().unwrap().assume_unresolved();
1162    let scim_value = write_txn.resolve_scim_interim(scim_int_value).unwrap();
1163
1164    let generic = serde_json::to_value(scim_value).unwrap();
1165    // Check that we can turn back into a vs from the generic version.
1166    let vs_inter = T::from_scim_json_put(generic).unwrap().assume_unresolved();
1167    let vs = write_txn.resolve_valueset_intermediate(vs_inter).unwrap();
1168    assert_eq!(&vs, expect_vs);
1169
1170    // For each additional check, assert they work as expected.
1171    for (jv, expect_vs) in additional_tests {
1172        let vs_inter = T::from_scim_json_put(jv.clone())
1173            .unwrap()
1174            .assume_unresolved();
1175        let vs = write_txn.resolve_valueset_intermediate(vs_inter).unwrap();
1176        assert_eq!(&vs, expect_vs);
1177    }
1178}