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