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