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