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