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