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