1use crate::be::dbentry::{DbEntry, DbEntryVers};
28use crate::be::dbvalue::DbValueSetV2;
29use crate::be::{IdxKey, IdxSlope};
30use crate::credential::apppwd::ApplicationPassword;
31use crate::credential::Credential;
32use crate::filter::{Filter, FilterInvalid, FilterResolved, FilterValidResolved};
33use crate::idm::ldap::ldap_vattr_map;
34use crate::modify::{Modify, ModifyInvalid, ModifyList, ModifyValid};
35use crate::prelude::*;
36use crate::repl::cid::Cid;
37use crate::repl::entry::EntryChangeState;
38use crate::repl::proto::{ReplEntryV1, ReplIncrementalEntryV1};
39use crate::schema::{SchemaAttribute, SchemaClass, SchemaTransaction};
40use crate::server::access::AccessEffectivePermission;
41use crate::value::{
42 ApiToken, CredentialType, IndexType, IntentTokenState, Oauth2Session, PartialValue, Session,
43 SyntaxType, Value,
44};
45use crate::valueset::{self, ScimResolveStatus, ValueSet, ValueSetSpn};
46use compact_jwt::JwsEs256Signer;
47use crypto_glue::s256::Sha256Output;
48use hashbrown::{HashMap, HashSet};
49use kanidm_proto::internal::ImageValue;
50use kanidm_proto::internal::{
51 ConsistencyError, Filter as ProtoFilter, OperationError, SchemaError, UiHint,
52};
53use kanidm_proto::scim_v1::server::ScimEffectiveAccess;
54use kanidm_proto::v1::Entry as ProtoEntry;
55use ldap3_proto::simple::{LdapPartialAttribute, LdapSearchResultEntry};
56use openssl::ec::EcKey;
57use openssl::pkey::{Private, Public};
58use std::cmp::Ordering;
59pub use std::collections::BTreeSet as Set;
60use std::collections::{BTreeMap as Map, BTreeMap, BTreeSet};
61use std::sync::Arc;
62use time::OffsetDateTime;
63use tracing::trace;
64use uuid::Uuid;
65use webauthn_rs::prelude::{
66 AttestationCaList, AttestedPasskey as AttestedPasskeyV4, Passkey as PasskeyV4,
67};
68
69pub type EntryInitNew = Entry<EntryInit, EntryNew>;
70pub type EntryInvalidNew = Entry<EntryInvalid, EntryNew>;
71pub type EntryRefreshNew = Entry<EntryRefresh, EntryNew>;
72pub type EntrySealedNew = Entry<EntrySealed, EntryNew>;
73pub type EntryValidCommitted = Entry<EntryValid, EntryCommitted>;
74pub type EntrySealedCommitted = Entry<EntrySealed, EntryCommitted>;
75pub type EntryInvalidCommitted = Entry<EntryInvalid, EntryCommitted>;
76pub type EntryReducedCommitted = Entry<EntryReduced, EntryCommitted>;
77pub type EntryTuple = (Arc<EntrySealedCommitted>, EntryInvalidCommitted);
78
79pub type EntryIncrementalNew = Entry<EntryIncremental, EntryNew>;
80pub type EntryIncrementalCommitted = Entry<EntryIncremental, EntryCommitted>;
81
82#[derive(Clone, Debug)]
95pub struct EntryNew; #[derive(Clone, Debug)]
99pub struct EntryCommitted {
100 id: u64,
101}
102
103#[derive(Clone, Debug)]
104pub struct EntryInit;
105
106#[derive(Clone, Debug)]
113pub struct EntryInvalid {
114 cid: Cid,
115 ecstate: EntryChangeState,
116}
117
118#[derive(Clone, Debug)]
120pub struct EntryRefresh {
121 ecstate: EntryChangeState,
122}
123
124#[derive(Clone, Debug)]
126pub struct EntryIncremental {
127 uuid: Uuid,
129 ecstate: EntryChangeState,
130}
131
132#[derive(Clone, Debug)]
138pub struct EntryValid {
139 uuid: Uuid,
141 ecstate: EntryChangeState,
142}
143
144#[derive(Clone, Debug)]
151pub struct EntrySealed {
152 uuid: Uuid,
153 ecstate: EntryChangeState,
154}
155
156#[derive(Clone, Debug)]
162pub struct EntryReduced {
163 uuid: Uuid,
164 effective_access: Option<Box<AccessEffectivePermission>>,
165}
166
167pub type Eattrs = Map<Attribute, ValueSet>;
170
171pub trait GetUuid {
172 fn get_uuid(&self) -> Uuid;
173}
174
175pub trait Committed {}
176
177impl Committed for EntrySealed {}
178impl Committed for EntryReduced {}
179
180pub(crate) fn compare_attrs(left: &Eattrs, right: &Eattrs) -> bool {
181 let allkeys: Set<&Attribute> = left
184 .keys()
185 .chain(right.keys())
186 .filter(|k| *k != &Attribute::LastModifiedCid && *k != &Attribute::CreatedAtCid)
187 .collect();
188
189 allkeys.into_iter().all(|k| {
190 let left_vs = left.get(k);
192 let right_vs = right.get(k);
193 let r = match (left_vs, right_vs) {
194 (Some(l), Some(r)) => l.eq(r),
195 _ => false,
196 };
197 if !r {
198 trace!(?k, ?left_vs, ?right_vs, "compare_attrs_allkeys");
199 }
200 r
201 })
202}
203
204pub struct Entry<VALID, STATE> {
231 valid: VALID,
232 state: STATE,
233 attrs: Eattrs,
235}
236
237impl<VALID, STATE> std::fmt::Debug for Entry<VALID, STATE>
238where
239 STATE: std::fmt::Debug,
240 VALID: std::fmt::Debug,
241{
242 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
243 f.debug_struct("Entry<EntrySealed, _>")
244 .field("state", &self.state)
245 .field("valid", &self.valid)
246 .field("attrs", &self.attrs)
247 .finish()
248 }
249}
250
251impl<STATE> std::fmt::Display for Entry<EntrySealed, STATE>
252where
253 STATE: Clone,
254{
255 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
256 write!(f, "{}", self.get_uuid())
257 }
258}
259
260impl<STATE> std::fmt::Display for Entry<EntryInit, STATE>
261where
262 STATE: Clone,
263{
264 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
265 write!(f, "Entry in initial state")
266 }
267}
268
269impl<STATE> Entry<EntryInit, STATE>
270where
271 STATE: Clone,
272{
273 pub fn get_uuid(&self) -> Option<Uuid> {
275 self.attrs
276 .get(&Attribute::Uuid)
277 .and_then(|vs| vs.to_uuid_single())
278 }
279}
280
281impl Default for Entry<EntryInit, EntryNew> {
282 fn default() -> Self {
283 Self::new()
284 }
285}
286
287impl FromIterator<(Attribute, ValueSet)> for EntryInitNew {
288 fn from_iter<I: IntoIterator<Item = (Attribute, ValueSet)>>(iter: I) -> Self {
289 let attrs = Eattrs::from_iter(iter);
290
291 Entry {
292 valid: EntryInit,
293 state: EntryNew,
294 attrs,
295 }
296 }
297}
298
299impl Entry<EntryInit, EntryNew> {
300 pub fn new() -> Self {
301 Entry {
302 valid: EntryInit,
304 state: EntryNew,
305 attrs: Map::new(),
306 }
307 }
308
309 pub fn from_proto_entry(
312 e: &ProtoEntry,
313 qs: &mut QueryServerWriteTransaction,
314 ) -> Result<Self, OperationError> {
315 trace!("from_proto_entry");
316 let map2: Result<Eattrs, OperationError> = e
323 .attrs
324 .iter()
325 .filter(|(_, v)| !v.is_empty())
326 .map(|(k, v)| {
327 trace!(?k, ?v, "attribute");
328 let attr_nk = Attribute::from(k.as_str());
329 let nv = valueset::from_result_value_iter(
330 v.iter().map(|vr| qs.clone_value(&attr_nk, vr)),
331 );
332 trace!(?nv, "new valueset transform");
333 match nv {
334 Ok(nvi) => Ok((attr_nk, nvi)),
335 Err(e) => Err(e),
336 }
337 })
338 .collect();
339
340 let x = map2?;
341
342 Ok(Entry {
343 state: EntryNew,
344 valid: EntryInit,
345 attrs: x,
346 })
347 }
348
349 #[instrument(level = "debug", skip_all)]
352 pub fn from_proto_entry_str(
353 es: &str,
354 qs: &mut QueryServerWriteTransaction,
355 ) -> Result<Self, OperationError> {
356 if cfg!(test) {
357 if es.len() > 256 {
358 let (dsp_es, _) = es.split_at(255);
359 trace!("Parsing -> {}...", dsp_es);
360 } else {
361 trace!("Parsing -> {}", es);
362 }
363 }
364 let pe: ProtoEntry = serde_json::from_str(es).map_err(|e| {
366 admin_error!(?e, "SerdeJson Failure");
369 OperationError::SerdeJsonError
370 })?;
371 Self::from_proto_entry(&pe, qs)
373 }
374
375 pub fn assign_cid(
378 mut self,
379 cid: Cid,
380 schema: &dyn SchemaTransaction,
381 ) -> Entry<EntryInvalid, EntryNew> {
382 let ecstate = EntryChangeState::new(&cid, &self.attrs, schema);
388
389 let cv = vs_cid![cid.clone()];
392 let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
393 let cv = vs_cid![cid.clone()];
394 let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
395
396 Entry {
397 valid: EntryInvalid { cid, ecstate },
398 state: EntryNew,
399 attrs: self.attrs,
400 }
401 }
402
403 pub fn compare(&self, rhs: &Entry<EntrySealed, EntryCommitted>) -> bool {
405 compare_attrs(&self.attrs, &rhs.attrs)
406 }
407
408 #[cfg(test)]
412 pub fn into_invalid_new(mut self) -> Entry<EntryInvalid, EntryNew> {
413 let cid = Cid::new_zero();
414 self.set_last_changed(cid.clone());
415
416 let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
417
418 Entry {
419 valid: EntryInvalid { cid, ecstate },
420 state: EntryNew,
421 attrs: self.attrs,
422 }
423 }
424
425 #[cfg(test)]
429 pub fn into_valid_new(mut self) -> Entry<EntryValid, EntryNew> {
430 let cid = Cid::new_zero();
431 self.set_last_changed(cid.clone());
432 let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
433
434 Entry {
435 valid: EntryValid {
436 ecstate,
437 uuid: self.get_uuid().expect("Invalid uuid"),
438 },
439 state: EntryNew,
440 attrs: self.attrs,
441 }
442 }
443
444 #[cfg(test)]
448 pub fn into_sealed_committed(mut self) -> Entry<EntrySealed, EntryCommitted> {
449 let cid = Cid::new_zero();
450 self.set_last_changed(cid.clone());
451 let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
452 let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
453 Entry {
454 valid: EntrySealed { uuid, ecstate },
455 state: EntryCommitted { id: 0 },
456 attrs: self.attrs,
457 }
458 }
459
460 #[cfg(test)]
464 pub fn into_sealed_new(mut self) -> Entry<EntrySealed, EntryNew> {
465 let cid = Cid::new_zero();
466 self.set_last_changed(cid.clone());
467 let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
468
469 Entry {
470 valid: EntrySealed {
471 uuid: self.get_uuid().expect("Invalid uuid"),
472 ecstate,
473 },
474 state: EntryNew,
475 attrs: self.attrs,
476 }
477 }
478
479 pub fn add_ava(&mut self, attr: Attribute, value: Value) {
485 self.add_ava_int(attr, value);
486 }
487
488 pub fn remove_ava(&mut self, attr: &Attribute) {
489 self.attrs.remove(attr);
490 }
491
492 pub fn set_ava_set(&mut self, attr: &Attribute, vs: ValueSet) {
494 self.attrs.insert(attr.clone(), vs);
495 }
496
497 pub fn set_ava<T>(&mut self, attr: Attribute, iter: T)
499 where
500 T: IntoIterator<Item = Value>,
501 {
502 self.set_ava_iter_int(attr, iter);
503 }
504
505 pub fn get_ava_mut<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<&mut ValueSet> {
506 self.attrs.get_mut(attr.as_ref())
507 }
508}
509
510impl From<SchemaAttribute> for EntryInitNew {
511 fn from(value: SchemaAttribute) -> Self {
512 EntryInitNew::from(&value)
513 }
514}
515
516impl From<&SchemaAttribute> for EntryInitNew {
517 fn from(s: &SchemaAttribute) -> Self {
518 let mut attrs = Eattrs::new();
520 attrs.insert(Attribute::AttributeName, vs_iutf8![s.name.as_str()]);
521 attrs.insert(Attribute::Description, vs_utf8![s.description.to_owned()]);
522 attrs.insert(Attribute::Uuid, vs_uuid![s.uuid]);
523 attrs.insert(Attribute::MultiValue, vs_bool![s.multivalue]);
524 attrs.insert(Attribute::Phantom, vs_bool![s.phantom]);
525 attrs.insert(Attribute::SyncAllowed, vs_bool![s.sync_allowed]);
526 attrs.insert(Attribute::Replicated, vs_bool![s.replicated.into()]);
527 attrs.insert(Attribute::Unique, vs_bool![s.unique]);
528 attrs.insert(Attribute::Indexed, vs_bool![s.indexed]);
529 attrs.insert(Attribute::Syntax, vs_syntax![s.syntax]);
530 attrs.insert(
531 Attribute::Class,
532 vs_iutf8![
533 EntryClass::Object.into(),
534 EntryClass::System.into(),
535 EntryClass::AttributeType.into()
536 ],
537 );
538
539 Entry {
542 valid: EntryInit,
543 state: EntryNew,
544 attrs,
545 }
546 }
547}
548
549impl From<SchemaClass> for EntryInitNew {
550 fn from(value: SchemaClass) -> Self {
551 EntryInitNew::from(&value)
552 }
553}
554
555impl From<&SchemaClass> for EntryInitNew {
556 fn from(s: &SchemaClass) -> Self {
557 let mut attrs = Eattrs::new();
558 attrs.insert(Attribute::ClassName, vs_iutf8![s.name.as_str()]);
559 attrs.insert(Attribute::Description, vs_utf8![s.description.to_owned()]);
560 attrs.insert(Attribute::SyncAllowed, vs_bool![s.sync_allowed]);
561 attrs.insert(Attribute::Uuid, vs_uuid![s.uuid]);
562 attrs.insert(
563 Attribute::Class,
564 vs_iutf8![
565 EntryClass::Object.into(),
566 EntryClass::System.into(),
567 EntryClass::ClassType.into()
568 ],
569 );
570
571 let vs_systemmay = ValueSetIutf8::from_iter(s.systemmay.iter().map(|sm| sm.as_str()));
572 if let Some(vs) = vs_systemmay {
573 attrs.insert(Attribute::SystemMay, vs);
574 }
575
576 let vs_systemmust = ValueSetIutf8::from_iter(s.systemmust.iter().map(|sm| sm.as_str()));
577 if let Some(vs) = vs_systemmust {
578 attrs.insert(Attribute::SystemMust, vs);
579 }
580
581 let vs_systemexcludes =
582 ValueSetIutf8::from_iter(s.systemexcludes.iter().map(|sm| sm.as_str()));
583 if let Some(vs) = vs_systemexcludes {
584 attrs.insert(Attribute::SystemExcludes, vs);
585 }
586
587 let vs_systemsupplements =
588 ValueSetIutf8::from_iter(s.systemsupplements.iter().map(|sm| sm.as_str()));
589 if let Some(vs) = vs_systemsupplements {
590 attrs.insert(Attribute::SystemSupplements, vs);
591 }
592
593 Entry {
594 valid: EntryInit,
595 state: EntryNew,
596 attrs,
597 }
598 }
599}
600
601impl Entry<EntryRefresh, EntryNew> {
602 pub fn from_repl_entry_v1(repl_entry: ReplEntryV1) -> Result<Self, OperationError> {
603 let (ecstate, mut attrs) = repl_entry.rehydrate()?;
605
606 let last_mod_cid = ecstate.get_max_cid();
609 let cv = vs_cid![last_mod_cid.clone()];
610 let _ = attrs.insert(Attribute::LastModifiedCid, cv);
611
612 let create_at_cid = ecstate.at();
613 let cv = vs_cid![create_at_cid.clone()];
614 let _ = attrs.insert(Attribute::CreatedAtCid, cv);
615
616 Ok(Entry {
617 valid: EntryRefresh { ecstate },
618 state: EntryNew,
619 attrs,
620 })
621 }
622}
623
624impl<STATE> Entry<EntryRefresh, STATE> {
625 pub fn validate(
626 self,
627 schema: &dyn SchemaTransaction,
628 ) -> Result<Entry<EntryValid, STATE>, SchemaError> {
629 let uuid: Uuid = self
630 .attrs
631 .get(&Attribute::Uuid)
632 .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
633 .and_then(|vs| {
634 vs.to_uuid_single()
635 .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
636 })?;
637
638 let ne = Entry {
640 valid: EntryValid {
641 uuid,
642 ecstate: self.valid.ecstate,
643 },
644 state: self.state,
645 attrs: self.attrs,
646 };
647
648 ne.validate(schema).map(|()| ne)
649 }
650}
651
652impl<STATE> Entry<EntryIncremental, STATE> {
653 pub fn get_uuid(&self) -> Uuid {
654 self.valid.uuid
655 }
656}
657
658impl Entry<EntryIncremental, EntryNew> {
659 fn stub_ecstate(&self) -> EntryChangeState {
660 self.valid.ecstate.stub()
661 }
662
663 pub fn rehydrate(repl_inc_entry: ReplIncrementalEntryV1) -> Result<Self, OperationError> {
664 let (uuid, ecstate, attrs) = repl_inc_entry.rehydrate()?;
665
666 Ok(Entry {
667 valid: EntryIncremental { uuid, ecstate },
668 state: EntryNew,
669 attrs,
670 })
671 }
672
673 pub(crate) fn is_add_conflict(&self, db_entry: &EntrySealedCommitted) -> bool {
674 use crate::repl::entry::State;
675 debug_assert_eq!(self.valid.uuid, db_entry.valid.uuid);
676 let self_cs = &self.valid.ecstate;
678 let db_cs = db_entry.get_changestate();
679
680 match (self_cs.current(), db_cs.current()) {
682 (State::Live { at: at_left, .. }, State::Live { at: at_right, .. }) => {
683 at_left != at_right
684 }
685 _ => false,
687 }
688 }
689
690 pub(crate) fn resolve_add_conflict(
691 &self,
692 cid: &Cid,
693 db_ent: &EntrySealedCommitted,
694 ) -> (Option<EntrySealedNew>, EntryIncrementalCommitted) {
695 use crate::repl::entry::State;
696 debug_assert_eq!(self.valid.uuid, db_ent.valid.uuid);
697 let self_cs = &self.valid.ecstate;
698 let db_cs = db_ent.get_changestate();
699
700 match (self_cs.current(), db_cs.current()) {
701 (
702 State::Live {
703 at: at_left,
704 changes: _changes_left,
705 },
706 State::Live {
707 at: at_right,
708 changes: _changes_right,
709 },
710 ) => {
711 debug_assert!(at_left != at_right);
712 if at_left > at_right {
723 trace!("RI > DE, return DE");
724 (
725 None,
726 Entry {
727 valid: EntryIncremental {
728 uuid: db_ent.valid.uuid,
729 ecstate: db_cs.clone(),
730 },
731 state: EntryCommitted {
732 id: db_ent.state.id,
733 },
734 attrs: db_ent.attrs.clone(),
735 },
736 )
737 }
738 else {
748 trace!("RI < DE, return RI");
749 let conflict = if at_right.s_uuid == cid.s_uuid {
751 trace!("Origin process conflict entry");
752 let mut cnf_ent = Entry {
755 valid: EntryInvalid {
756 cid: cid.clone(),
757 ecstate: db_cs.clone(),
758 },
759 state: EntryNew,
760 attrs: db_ent.attrs.clone(),
761 };
762
763 cnf_ent.add_ava(Attribute::SourceUuid, Value::Uuid(db_ent.valid.uuid));
765
766 let new_uuid = Uuid::new_v4();
768 cnf_ent.purge_ava(Attribute::Uuid);
769 cnf_ent.add_ava(Attribute::Uuid, Value::Uuid(new_uuid));
770 cnf_ent.add_ava(Attribute::Class, EntryClass::Recycled.into());
771 cnf_ent.add_ava(Attribute::Class, EntryClass::Conflict.into());
772
773 let cv = vs_cid![cid.clone()];
777 let _ = cnf_ent.attrs.insert(Attribute::LastModifiedCid, cv);
778 let cv = vs_cid![cid.clone()];
780 let _ = cnf_ent.attrs.insert(Attribute::CreatedAtCid, cv);
781
782 let Entry {
786 valid: EntryInvalid { cid: _, ecstate },
787 state,
788 attrs,
789 } = cnf_ent;
790
791 let cnf_ent = Entry {
792 valid: EntrySealed {
793 uuid: new_uuid,
794 ecstate,
795 },
796 state,
797 attrs,
798 };
799
800 Some(cnf_ent)
801 } else {
802 None
803 };
804
805 let mut attrs = self.attrs.clone();
809 let ecstate = self_cs.clone();
810
811 let last_mod_cid = ecstate.get_max_cid();
812 let cv = vs_cid![last_mod_cid.clone()];
813 let _ = attrs.insert(Attribute::LastModifiedCid, cv);
814
815 let create_at_cid = ecstate.at();
816 let cv = vs_cid![create_at_cid.clone()];
817 let _ = attrs.insert(Attribute::CreatedAtCid, cv);
818
819 (
820 conflict,
821 Entry {
822 valid: EntryIncremental {
823 uuid: self.valid.uuid,
824 ecstate,
825 },
826 state: EntryCommitted {
827 id: db_ent.state.id,
828 },
829 attrs,
830 },
831 )
832 }
833 }
834 _ => unreachable!(),
838 }
839 }
840
841 pub(crate) fn merge_state(
842 &self,
843 db_ent: &EntrySealedCommitted,
844 schema: &dyn SchemaTransaction,
845 trim_cid: &Cid,
846 ) -> EntryIncrementalCommitted {
847 use crate::repl::entry::State;
848
849 debug_assert_eq!(self.valid.uuid, db_ent.valid.uuid);
851
852 let self_cs = &self.valid.ecstate;
855 let db_cs = db_ent.get_changestate();
856
857 match (self_cs.current(), db_cs.current()) {
858 (
859 State::Live {
860 at: at_left,
861 changes: changes_left,
862 },
863 State::Live {
864 at: at_right,
865 changes: changes_right,
866 },
867 ) => {
868 debug_assert_eq!(at_left, at_right);
869 let mut attr_set: Vec<_> =
874 changes_left.keys().chain(changes_right.keys()).collect();
875 attr_set.shrink_to_fit();
876 attr_set.sort_unstable();
877 attr_set.dedup();
878
879 let mut changes = BTreeMap::default();
881 let mut eattrs = Eattrs::default();
882
883 for attr_name in attr_set.into_iter() {
885 match (changes_left.get(attr_name), changes_right.get(attr_name)) {
886 (Some(cid_left), Some(cid_right)) => {
887 let take_left = cid_left > cid_right;
894
895 match (self.attrs.get(attr_name), db_ent.attrs.get(attr_name)) {
896 (Some(vs_left), Some(vs_right)) if take_left => {
897 changes.insert(attr_name.clone(), cid_left.clone());
898 #[allow(clippy::todo)]
899 if let Some(merged_attr_state) =
900 vs_left.repl_merge_valueset(vs_right, trim_cid)
901 {
902 eattrs.insert(attr_name.clone(), merged_attr_state);
905 } else {
906 eattrs.insert(attr_name.clone(), vs_left.clone());
907 }
908 }
909 (Some(vs_left), Some(vs_right)) => {
910 changes.insert(attr_name.clone(), cid_right.clone());
911 #[allow(clippy::todo)]
912 if let Some(merged_attr_state) =
913 vs_right.repl_merge_valueset(vs_left, trim_cid)
914 {
915 eattrs.insert(attr_name.clone(), merged_attr_state);
918 } else {
919 eattrs.insert(attr_name.clone(), vs_right.clone());
920 }
921 }
922 (Some(vs_left), None) if take_left => {
923 changes.insert(attr_name.clone(), cid_left.clone());
924 eattrs.insert(attr_name.clone(), vs_left.clone());
925 }
926 (Some(_vs_left), None) => {
927 changes.insert(attr_name.clone(), cid_right.clone());
928 }
930 (None, Some(_vs_right)) if take_left => {
931 changes.insert(attr_name.clone(), cid_left.clone());
932 }
934 (None, Some(vs_right)) => {
935 changes.insert(attr_name.clone(), cid_right.clone());
936 eattrs.insert(attr_name.clone(), vs_right.clone());
937 }
938 (None, None) if take_left => {
939 changes.insert(attr_name.clone(), cid_left.clone());
940 }
942 (None, None) => {
943 changes.insert(attr_name.clone(), cid_right.clone());
944 }
946 }
947 }
949 (Some(cid_left), None) => {
950 changes.insert(attr_name.clone(), cid_left.clone());
952 if let Some(valueset) = self.attrs.get(attr_name) {
953 eattrs.insert(attr_name.clone(), valueset.clone());
954 }
955 }
956 (None, Some(cid_right)) => {
957 changes.insert(attr_name.clone(), cid_right.clone());
959 if let Some(valueset) = db_ent.attrs.get(attr_name) {
960 eattrs.insert(attr_name.clone(), valueset.clone());
961 }
962 }
963 (None, None) => {
964 debug_assert!(false);
966 }
967 }
968 }
969
970 let mut ecstate = EntryChangeState::build(State::Live {
971 at: at_left.clone(),
972 changes,
973 });
974
975 ecstate.retain(|k, _| schema.is_replicated(k));
979
980 let cv = vs_cid![ecstate.get_max_cid().clone()];
981 let _ = eattrs.insert(Attribute::LastModifiedCid, cv);
982
983 let cv = vs_cid![ecstate.at().clone()];
984 let _ = eattrs.insert(Attribute::CreatedAtCid, cv);
985
986 Entry {
987 valid: EntryIncremental {
988 uuid: self.valid.uuid,
989 ecstate,
990 },
991 state: EntryCommitted {
992 id: db_ent.state.id,
993 },
994 attrs: eattrs,
995 }
996 }
997 (State::Tombstone { at: left_at }, State::Live { .. }) => {
998 let mut attrs_new: Eattrs = Map::new();
1002 let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()];
1003 let last_mod_ava = vs_cid![left_at.clone()];
1004 let created_ava = vs_cid![left_at.clone()];
1005
1006 attrs_new.insert(Attribute::Uuid, vs_uuid![self.valid.uuid]);
1007 attrs_new.insert(Attribute::Class, class_ava);
1008 attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava);
1009 attrs_new.insert(Attribute::CreatedAtCid, created_ava);
1010
1011 Entry {
1012 valid: EntryIncremental {
1013 uuid: self.valid.uuid,
1014 ecstate: self.valid.ecstate.clone(),
1015 },
1016 state: EntryCommitted {
1017 id: db_ent.state.id,
1018 },
1019 attrs: attrs_new,
1020 }
1021 }
1022 (State::Live { .. }, State::Tombstone { .. }) => {
1023 Entry {
1031 valid: EntryIncremental {
1032 uuid: db_ent.valid.uuid,
1033 ecstate: db_ent.valid.ecstate.clone(),
1034 },
1035 state: EntryCommitted {
1036 id: db_ent.state.id,
1037 },
1038 attrs: db_ent.attrs.clone(),
1039 }
1040 }
1041 (State::Tombstone { at: left_at }, State::Tombstone { at: right_at }) => {
1042 let (at, ecstate) = if left_at < right_at {
1047 (left_at, self.valid.ecstate.clone())
1048 } else {
1049 (right_at, db_ent.valid.ecstate.clone())
1050 };
1051
1052 let mut attrs_new: Eattrs = Map::new();
1053 let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()];
1054 let last_mod_ava = vs_cid![at.clone()];
1055 let created_ava = vs_cid![at.clone()];
1056
1057 attrs_new.insert(Attribute::Uuid, vs_uuid![db_ent.valid.uuid]);
1058 attrs_new.insert(Attribute::Class, class_ava);
1059 attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava);
1060 attrs_new.insert(Attribute::CreatedAtCid, created_ava);
1061
1062 Entry {
1063 valid: EntryIncremental {
1064 uuid: db_ent.valid.uuid,
1065 ecstate,
1066 },
1067 state: EntryCommitted {
1068 id: db_ent.state.id,
1069 },
1070 attrs: attrs_new,
1071 }
1072 }
1073 }
1074 }
1075}
1076
1077impl Entry<EntryIncremental, EntryCommitted> {
1078 pub(crate) fn validate_repl(self, schema: &dyn SchemaTransaction) -> EntryValidCommitted {
1079 let mut ne = Entry {
1084 valid: EntryValid {
1085 uuid: self.valid.uuid,
1086 ecstate: self.valid.ecstate,
1087 },
1088 state: self.state,
1089 attrs: self.attrs,
1090 };
1091
1092 if let Err(e) = ne.validate(schema) {
1093 warn!(uuid = ?self.valid.uuid, err = ?e, "Entry failed schema check, moving to a conflict state");
1094 ne.add_ava_int(Attribute::Class, EntryClass::Recycled.into());
1095 ne.add_ava_int(Attribute::Class, EntryClass::Conflict.into());
1096 ne.add_ava_int(Attribute::SourceUuid, Value::Uuid(self.valid.uuid));
1097 }
1098 ne
1099 }
1100}
1101
1102impl<STATE> Entry<EntryInvalid, STATE> {
1103 pub(crate) fn get_uuid(&self) -> Option<Uuid> {
1104 self.attrs
1105 .get(&Attribute::Uuid)
1106 .and_then(|vs| vs.to_uuid_single())
1107 }
1108
1109 pub fn validate(
1112 self,
1113 schema: &dyn SchemaTransaction,
1114 ) -> Result<Entry<EntryValid, STATE>, SchemaError> {
1115 let uuid: Uuid = self
1116 .attrs
1117 .get(&Attribute::Uuid)
1118 .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
1119 .and_then(|vs| {
1120 vs.to_uuid_single()
1121 .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
1122 })?;
1123
1124 let ne = Entry {
1126 valid: EntryValid {
1127 uuid,
1128 ecstate: self.valid.ecstate,
1129 },
1130 state: self.state,
1131 attrs: self.attrs,
1132 };
1133
1134 ne.validate(schema).map(|()| ne)
1135 }
1136
1137 pub(crate) fn get_ava_refer_mut<A: AsRef<Attribute>>(
1141 &mut self,
1142 attr: A,
1143 ) -> Option<&mut BTreeSet<Uuid>> {
1144 self.get_ava_mut(attr).and_then(|vs| vs.as_refer_set_mut())
1145 }
1146
1147 pub(crate) fn get_ava_mut<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<&mut ValueSet> {
1148 let attr_ref = attr.as_ref();
1149 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
1150 self.attrs.get_mut(attr.as_ref())
1151 }
1152}
1153
1154impl<VALID, STATE> Clone for Entry<VALID, STATE>
1155where
1156 VALID: Clone,
1157 STATE: Clone,
1158{
1159 fn clone(&self) -> Entry<VALID, STATE> {
1161 Entry {
1162 valid: self.valid.clone(),
1163 state: self.state.clone(),
1164 attrs: self.attrs.clone(),
1165 }
1166 }
1167}
1168
1169impl Entry<EntryInvalid, EntryCommitted> {
1170 #[cfg(test)]
1174 pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
1175 let uuid = self.get_uuid().expect("Invalid uuid");
1176 Entry {
1177 valid: EntryValid {
1178 uuid,
1179 ecstate: self.valid.ecstate,
1180 },
1181 state: EntryNew,
1182 attrs: self.attrs,
1183 }
1184 }
1185
1186 pub fn to_recycled(mut self) -> Self {
1188 self.add_ava(Attribute::Class, EntryClass::Recycled.into());
1190
1191 Entry {
1195 valid: self.valid,
1196 state: self.state,
1197 attrs: self.attrs,
1198 }
1199 }
1200
1201 pub fn to_conflict<T>(&mut self, iter: T)
1203 where
1204 T: IntoIterator<Item = Uuid>,
1205 {
1206 self.add_ava(Attribute::Class, EntryClass::Recycled.into());
1207 self.add_ava(Attribute::Class, EntryClass::Conflict.into());
1208 for source_uuid in iter {
1210 self.add_ava(Attribute::SourceUuid, Value::Uuid(source_uuid));
1211 }
1212 }
1213
1214 pub fn to_revived(mut self) -> Self {
1216 self.remove_ava(Attribute::Class, &EntryClass::Recycled.into());
1218 self.remove_ava(Attribute::Class, &EntryClass::Conflict.into());
1219
1220 self.purge_ava(Attribute::CascadeDeleted);
1221 self.purge_ava(Attribute::SourceUuid);
1222 self.purge_ava(Attribute::RecycledDirectMemberOf);
1223
1224 Entry {
1228 valid: self.valid,
1229 state: self.state,
1230 attrs: self.attrs,
1231 }
1232 }
1233}
1234impl Entry<EntryInvalid, EntryNew> {
1237 #[cfg(test)]
1240 pub fn into_init_new(self) -> Entry<EntryInit, EntryNew> {
1241 Entry {
1242 valid: EntryInit,
1243 state: EntryNew,
1244 attrs: self.attrs,
1245 }
1246 }
1247
1248 #[cfg(test)]
1252 pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
1253 let uuid = self.get_uuid().expect("Invalid uuid");
1254 Entry {
1255 valid: EntryValid {
1256 uuid,
1257 ecstate: self.valid.ecstate,
1258 },
1259 state: EntryNew,
1260 attrs: self.attrs,
1261 }
1262 }
1263
1264 #[cfg(test)]
1268 pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1269 let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
1270 Entry {
1271 valid: EntrySealed {
1272 uuid,
1273 ecstate: self.valid.ecstate,
1274 },
1275 state: EntryCommitted { id: 0 },
1276 attrs: self.attrs,
1277 }
1278 }
1279
1280 #[cfg(test)]
1284 pub fn into_valid_committed(self) -> Entry<EntryValid, EntryCommitted> {
1285 let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
1286 Entry {
1287 valid: EntryValid {
1288 uuid,
1289 ecstate: self.valid.ecstate,
1290 },
1291 state: EntryCommitted { id: 0 },
1292 attrs: self.attrs,
1293 }
1294 }
1295}
1296
1297impl Entry<EntryInvalid, EntryCommitted> {
1298 #[cfg(test)]
1302 pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1303 let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
1304 Entry {
1305 valid: EntrySealed {
1306 uuid,
1307 ecstate: self.valid.ecstate,
1308 },
1309 state: self.state,
1310 attrs: self.attrs,
1311 }
1312 }
1313}
1314
1315impl Entry<EntrySealed, EntryNew> {
1316 #[cfg(test)]
1320 pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1321 Entry {
1322 valid: self.valid,
1323 state: EntryCommitted { id: 0 },
1324 attrs: self.attrs,
1325 }
1326 }
1327
1328 pub fn into_sealed_committed_id(self, id: u64) -> Entry<EntrySealed, EntryCommitted> {
1331 Entry {
1332 valid: self.valid,
1333 state: EntryCommitted { id },
1334 attrs: self.attrs,
1335 }
1336 }
1337
1338 pub fn compare(&self, rhs: &Entry<EntrySealed, EntryNew>) -> bool {
1339 compare_attrs(&self.attrs, &rhs.attrs)
1340 }
1341}
1342
1343type IdxDiff<'a> =
1344 Vec<Result<(&'a Attribute, IndexType, String), (&'a Attribute, IndexType, String)>>;
1345
1346impl<VALID> Entry<VALID, EntryCommitted> {
1347 pub fn get_id(&self) -> u64 {
1349 self.state.id
1350 }
1351}
1352
1353impl<STATE> Entry<EntrySealed, STATE> {
1354 pub fn into_init(self) -> Entry<EntryInit, STATE> {
1355 Entry {
1356 valid: EntryInit,
1357 state: self.state,
1358 attrs: self.attrs,
1359 }
1360 }
1361}
1362
1363impl Entry<EntrySealed, EntryCommitted> {
1364 #[cfg(test)]
1365 pub(crate) fn get_last_changed(&self) -> Cid {
1366 self.valid.ecstate.get_max_cid().clone()
1367 }
1368
1369 #[cfg(test)]
1371 pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1372 self
1374 }
1375
1376 pub(crate) fn stub_sealed_committed_id(
1377 id: u64,
1378 ctx_ent: &EntryIncrementalNew,
1379 ) -> EntrySealedCommitted {
1380 let uuid = ctx_ent.get_uuid();
1381 let ecstate = ctx_ent.stub_ecstate();
1382
1383 Entry {
1384 valid: EntrySealed { uuid, ecstate },
1385 state: EntryCommitted { id },
1386 attrs: Default::default(),
1387 }
1388 }
1389
1390 pub fn insert_claim(&mut self, value: &str) {
1393 self.add_ava_int(Attribute::Claim, Value::new_iutf8(value));
1394 }
1395
1396 pub fn compare(&self, rhs: &Entry<EntrySealed, EntryCommitted>) -> bool {
1397 compare_attrs(&self.attrs, &rhs.attrs)
1398 }
1399
1400 pub fn to_dbentry(&self) -> DbEntry {
1402 DbEntry {
1405 ent: DbEntryVers::V3 {
1406 changestate: self.valid.ecstate.to_db_changestate(),
1407 attrs: self
1408 .attrs
1409 .iter()
1410 .map(|(k, vs)| {
1411 let dbvs: DbValueSetV2 = vs.to_db_valueset_v2();
1412 (k.clone(), dbvs)
1413 })
1414 .collect(),
1415 },
1416 }
1417 }
1418
1419 #[inline]
1420 fn get_name2uuid_cands(&self) -> Set<String> {
1423 let cands = [Attribute::Spn, Attribute::Name, Attribute::GidNumber];
1429 cands
1430 .iter()
1431 .filter_map(|cand| {
1432 self.attrs
1433 .get(cand)
1434 .map(|vs| vs.to_proto_string_clone_iter())
1435 })
1436 .flatten()
1437 .collect()
1438 }
1439
1440 #[inline]
1441 fn get_externalid2uuid(&self) -> Option<String> {
1444 self.attrs
1445 .get(&Attribute::SyncExternalId)
1446 .and_then(|vs| vs.to_proto_string_single())
1447 }
1448
1449 #[inline]
1450 pub(crate) fn get_uuid2spn(&self) -> Value {
1453 self.attrs
1454 .get(&Attribute::Spn)
1455 .and_then(|vs| vs.to_value_single())
1456 .or_else(|| {
1457 self.attrs
1458 .get(&Attribute::Name)
1459 .and_then(|vs| vs.to_value_single())
1460 })
1461 .unwrap_or_else(|| Value::Uuid(self.get_uuid()))
1462 }
1463
1464 #[inline]
1465 pub(crate) fn get_uuid2rdn(&self) -> String {
1469 self.attrs
1470 .get(&Attribute::Spn)
1471 .and_then(|vs| vs.to_proto_string_single().map(|v| format!("spn={v}")))
1472 .or_else(|| {
1473 self.attrs
1474 .get(&Attribute::Name)
1475 .and_then(|vs| vs.to_proto_string_single().map(|v| format!("name={v}")))
1476 })
1477 .unwrap_or_else(|| format!("uuid={}", self.get_uuid().as_hyphenated()))
1478 }
1479
1480 pub(crate) fn idx_name2uuid_diff(
1483 pre: Option<&Self>,
1484 post: Option<&Self>,
1485 ) -> (
1486 Option<Set<String>>,
1488 Option<Set<String>>,
1490 ) {
1491 match (pre, post) {
1493 (None, None) => {
1494 (None, None)
1496 }
1497 (None, Some(b)) => {
1498 (Some(b.get_name2uuid_cands()), None)
1501 }
1502 (Some(a), None) => {
1503 (None, Some(a.get_name2uuid_cands()))
1505 }
1506 (Some(a), Some(b)) => {
1507 let pre_set = a.get_name2uuid_cands();
1508 let post_set = b.get_name2uuid_cands();
1509
1510 let add_set: Set<_> = post_set.difference(&pre_set).cloned().collect();
1512 let rem_set: Set<_> = pre_set.difference(&post_set).cloned().collect();
1514 (Some(add_set), Some(rem_set))
1515 }
1516 }
1517 }
1518
1519 pub(crate) fn idx_externalid2uuid_diff(
1521 pre: Option<&Self>,
1522 post: Option<&Self>,
1523 ) -> (Option<String>, Option<String>) {
1524 match (pre, post) {
1525 (None, None) => {
1526 (None, None)
1528 }
1529 (None, Some(b)) => {
1530 (b.get_externalid2uuid(), None)
1532 }
1533 (Some(a), None) => {
1534 (None, a.get_externalid2uuid())
1536 }
1537 (Some(a), Some(b)) => {
1538 let ia = a.get_externalid2uuid();
1539 let ib = b.get_externalid2uuid();
1540 if ia != ib {
1541 (ib, ia)
1544 } else {
1545 (None, None)
1547 }
1548 }
1549 }
1550 }
1551
1552 pub(crate) fn idx_uuid2spn_diff(
1555 pre: Option<&Self>,
1556 post: Option<&Self>,
1557 ) -> Option<Result<Value, ()>> {
1558 match (pre, post) {
1559 (None, None) => {
1560 None
1562 }
1563 (None, Some(b)) => {
1564 Some(Ok(b.get_uuid2spn()))
1566 }
1567 (Some(_a), None) => {
1568 Some(Err(()))
1570 }
1571 (Some(a), Some(b)) => {
1572 let ia = a.get_uuid2spn();
1573 let ib = b.get_uuid2spn();
1574 if ia != ib {
1575 Some(Ok(ib))
1577 } else {
1578 None
1580 }
1581 }
1582 }
1583 }
1584
1585 pub(crate) fn idx_uuid2rdn_diff(
1588 pre: Option<&Self>,
1589 post: Option<&Self>,
1590 ) -> Option<Result<String, ()>> {
1591 match (pre, post) {
1592 (None, None) => {
1593 None
1595 }
1596 (None, Some(b)) => {
1597 Some(Ok(b.get_uuid2rdn()))
1599 }
1600 (Some(_a), None) => {
1601 Some(Err(()))
1603 }
1604 (Some(a), Some(b)) => {
1605 let ia = a.get_uuid2rdn();
1606 let ib = b.get_uuid2rdn();
1607 if ia != ib {
1608 Some(Ok(ib))
1610 } else {
1611 None
1613 }
1614 }
1615 }
1616 }
1617
1618 pub(crate) fn idx_diff<'a>(
1621 idxmeta: &'a HashMap<IdxKey, IdxSlope>,
1622 pre: Option<&Self>,
1623 post: Option<&Self>,
1624 ) -> IdxDiff<'a> {
1625 match (pre, post) {
1630 (None, None) => {
1631 Vec::with_capacity(0)
1633 }
1634 (Some(pre_e), None) => {
1635 idxmeta
1637 .keys()
1638 .flat_map(|ikey| {
1639 match pre_e.get_ava_set(&ikey.attr) {
1640 None => Vec::with_capacity(0),
1641 Some(vs) => {
1642 let changes: Vec<Result<_, _>> = match ikey.itype {
1643 IndexType::Equality => {
1644 vs.generate_idx_eq_keys()
1646 .into_iter()
1647 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1648 .collect()
1649 }
1650 IndexType::Presence => {
1651 vec![Err((&ikey.attr, ikey.itype, "_".to_string()))]
1652 }
1653 IndexType::SubString => vs
1654 .generate_idx_sub_keys()
1655 .into_iter()
1656 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1657 .collect(),
1658 IndexType::Ordering => vs
1659 .generate_idx_ord_keys()
1660 .into_iter()
1661 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1662 .collect(),
1663 };
1664 changes
1665 }
1666 }
1667 })
1668 .collect()
1669 }
1670 (None, Some(post_e)) => {
1671 idxmeta
1673 .keys()
1674 .flat_map(|ikey| {
1675 match post_e.get_ava_set(&ikey.attr) {
1676 None => Vec::with_capacity(0),
1677 Some(vs) => {
1678 let changes: Vec<Result<_, _>> = match ikey.itype {
1679 IndexType::Equality => vs
1680 .generate_idx_eq_keys()
1681 .into_iter()
1682 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1683 .collect(),
1684 IndexType::Presence => {
1685 vec![Ok((&ikey.attr, ikey.itype, "_".to_string()))]
1686 }
1687 IndexType::SubString => vs
1688 .generate_idx_sub_keys()
1689 .into_iter()
1690 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1691 .collect(),
1692 IndexType::Ordering => vs
1693 .generate_idx_ord_keys()
1694 .into_iter()
1695 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1696 .collect(),
1697 };
1698 changes
1701 }
1702 }
1703 })
1704 .collect()
1705 }
1706 (Some(pre_e), Some(post_e)) => {
1707 assert_eq!(pre_e.state.id, post_e.state.id);
1708 idxmeta
1709 .keys()
1710 .flat_map(|ikey| {
1711 match (
1712 pre_e.get_ava_set(&ikey.attr),
1713 post_e.get_ava_set(&ikey.attr),
1714 ) {
1715 (None, None) => {
1716 Vec::with_capacity(0)
1718 }
1719 (Some(pre_vs), None) => {
1720 let changes: Vec<Result<_, _>> = match ikey.itype {
1722 IndexType::Equality => {
1723 pre_vs
1726 .generate_idx_eq_keys()
1727 .into_iter()
1728 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1729 .collect()
1730 }
1731 IndexType::Presence => {
1732 vec![Err((&ikey.attr, ikey.itype, "_".to_string()))]
1733 }
1734 IndexType::SubString => pre_vs
1735 .generate_idx_sub_keys()
1736 .into_iter()
1737 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1738 .collect(),
1739 IndexType::Ordering => pre_vs
1740 .generate_idx_ord_keys()
1741 .into_iter()
1742 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1743 .collect(),
1744 };
1745 changes
1746 }
1747 (None, Some(post_vs)) => {
1748 let changes: Vec<Result<_, _>> = match ikey.itype {
1750 IndexType::Equality => {
1751 post_vs
1754 .generate_idx_eq_keys()
1755 .into_iter()
1756 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1757 .collect()
1758 }
1759 IndexType::Presence => {
1760 vec![Ok((&ikey.attr, ikey.itype, "_".to_string()))]
1761 }
1762 IndexType::SubString => post_vs
1763 .generate_idx_sub_keys()
1764 .into_iter()
1765 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1766 .collect(),
1767 IndexType::Ordering => post_vs
1768 .generate_idx_ord_keys()
1769 .into_iter()
1770 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1771 .collect(),
1772 };
1773 changes
1774 }
1775 (Some(pre_vs), Some(post_vs)) => {
1776 let (mut pre_idx_keys, mut post_idx_keys) = match ikey.itype {
1778 IndexType::Equality => (
1779 pre_vs.generate_idx_eq_keys(),
1780 post_vs.generate_idx_eq_keys(),
1781 ),
1782 IndexType::Presence => {
1783 (Vec::with_capacity(0), Vec::with_capacity(0))
1785 }
1786 IndexType::SubString => (
1787 pre_vs.generate_idx_sub_keys(),
1788 post_vs.generate_idx_sub_keys(),
1789 ),
1790 IndexType::Ordering => (
1791 pre_vs.generate_idx_ord_keys(),
1792 post_vs.generate_idx_ord_keys(),
1793 ),
1794 };
1795
1796 let sz = if pre_idx_keys.len() > post_idx_keys.len() {
1797 pre_idx_keys.len()
1798 } else {
1799 post_idx_keys.len()
1800 };
1801
1802 let mut added_vs = Vec::with_capacity(sz);
1803 let mut removed_vs = Vec::with_capacity(sz);
1804
1805 if sz > 0 {
1806 pre_idx_keys.sort_unstable();
1807 post_idx_keys.sort_unstable();
1808
1809 let mut pre_iter = pre_idx_keys.iter();
1810 let mut post_iter = post_idx_keys.iter();
1811
1812 let mut pre = pre_iter.next();
1813 let mut post = post_iter.next();
1814
1815 loop {
1816 match (pre, post) {
1817 (Some(a), Some(b)) => {
1818 match a.cmp(b) {
1819 Ordering::Less => {
1820 removed_vs.push(a.clone());
1821 pre = pre_iter.next();
1822 }
1823 Ordering::Equal => {
1824 pre = pre_iter.next();
1826 post = post_iter.next();
1827 }
1828 Ordering::Greater => {
1829 added_vs.push(b.clone());
1830 post = post_iter.next();
1831 }
1832 }
1833 }
1834 (Some(a), None) => {
1835 removed_vs.push(a.clone());
1836 pre = pre_iter.next();
1837 }
1838 (None, Some(b)) => {
1839 added_vs.push(b.clone());
1840 post = post_iter.next();
1841 }
1842 (None, None) => {
1843 break;
1844 }
1845 }
1846 }
1847 } let mut diff =
1850 Vec::with_capacity(removed_vs.len() + added_vs.len());
1851
1852 match ikey.itype {
1853 IndexType::SubString
1854 | IndexType::Ordering
1855 | IndexType::Equality => {
1856 removed_vs
1857 .into_iter()
1858 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1859 .for_each(|v| diff.push(v));
1860 added_vs
1861 .into_iter()
1862 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1863 .for_each(|v| diff.push(v));
1864 }
1865 IndexType::Presence => {
1866 }
1868 };
1869 diff
1871 }
1872 }
1873 })
1874 .collect()
1875 }
1877 }
1878 }
1879
1880 pub fn from_dbentry(db_e: DbEntry, id: u64) -> Option<Self> {
1881 let (attrs, ecstate) = match db_e.ent {
1884 DbEntryVers::V3 { changestate, attrs } => {
1885 let ecstate = EntryChangeState::from_db_changestate(changestate);
1886
1887 let r_attrs = attrs
1888 .into_iter()
1889 .filter(|(_k, vs)| !vs.is_empty())
1891 .map(|(k, dbvs)| {
1892 valueset::from_db_valueset_v2(dbvs)
1893 .map(|vs: ValueSet| (k, vs))
1894 .map_err(|e| {
1895 error!(?e, "from_dbentry failed");
1896 })
1897 })
1898 .collect::<Result<Eattrs, ()>>()
1899 .ok()?;
1900
1901 (r_attrs, ecstate)
1902 }
1903 };
1904
1905 let uuid = attrs
1906 .get(&Attribute::Uuid)
1907 .and_then(|vs| vs.to_uuid_single())?;
1908
1909 Some(Entry {
1910 valid: EntrySealed { uuid, ecstate },
1911 state: EntryCommitted { id },
1912 attrs,
1913 })
1914 }
1915
1916 #[cfg(test)]
1924 pub(crate) fn into_reduced(self) -> Entry<EntryReduced, EntryCommitted> {
1925 Entry {
1926 valid: EntryReduced {
1927 uuid: self.valid.uuid,
1928 effective_access: None,
1929 },
1930 state: self.state,
1931 attrs: self.attrs,
1932 }
1933 }
1934
1935 pub fn reduce_attributes(
1938 &self,
1939 allowed_attrs: &BTreeSet<Attribute>,
1940 effective_access: Option<Box<AccessEffectivePermission>>,
1941 ) -> Entry<EntryReduced, EntryCommitted> {
1942 let f_attrs: Map<_, _> = self
1944 .attrs
1945 .iter()
1946 .filter_map(|(k, v)| {
1947 if allowed_attrs.contains(k) {
1948 Some((k.clone(), v.clone()))
1949 } else {
1950 None
1951 }
1952 })
1953 .collect();
1954
1955 let valid = EntryReduced {
1956 uuid: self.valid.uuid,
1957 effective_access,
1958 };
1959 let state = self.state.clone();
1960
1961 Entry {
1962 valid,
1963 state,
1964 attrs: f_attrs,
1965 }
1966 }
1967
1968 pub fn to_tombstone(&self, cid: Cid) -> Entry<EntryInvalid, EntryCommitted> {
1970 let mut ecstate = self.valid.ecstate.clone();
1971 let mut attrs_new: Eattrs = Map::new();
1973
1974 let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()];
1975 let last_mod_ava = vs_cid![cid.clone()];
1976 let created_ava = vs_cid![cid.clone()];
1977
1978 attrs_new.insert(Attribute::Uuid, vs_uuid![self.get_uuid()]);
1979 attrs_new.insert(Attribute::Class, class_ava);
1980 attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava);
1981 attrs_new.insert(Attribute::CreatedAtCid, created_ava);
1982
1983 ecstate.tombstone(&cid);
1985
1986 Entry {
1987 valid: EntryInvalid { cid, ecstate },
1988 state: self.state.clone(),
1989 attrs: attrs_new,
1990 }
1991 }
1992
1993 pub fn into_valid(self, ecstate: EntryChangeState) -> Entry<EntryValid, EntryCommitted> {
1995 Entry {
1996 valid: EntryValid {
1997 uuid: self.valid.uuid,
1998 ecstate,
1999 },
2000 state: self.state,
2001 attrs: self.attrs,
2002 }
2003 }
2004
2005 pub fn verify(
2006 &self,
2007 schema: &dyn SchemaTransaction,
2008 results: &mut Vec<Result<(), ConsistencyError>>,
2009 ) {
2010 self.valid
2011 .ecstate
2012 .verify(schema, &self.attrs, self.state.id, results);
2013 }
2014}
2015
2016impl<STATE> Entry<EntryValid, STATE> {
2017 fn validate(&self, schema: &dyn SchemaTransaction) -> Result<(), SchemaError> {
2018 let schema_classes = schema.get_classes();
2019 let schema_attributes = schema.get_attributes();
2020
2021 trace!(?self.attrs, "Entry::validate -> target");
2023
2024 if !self.attribute_pres(Attribute::Class) {
2026 return Err(SchemaError::NoClassFound);
2028 }
2029
2030 if self.attribute_equality(Attribute::Class, &EntryClass::Conflict.into()) {
2031 trace!("Skipping schema validation on conflict entry");
2033 return Ok(());
2034 };
2035
2036 let recycled = self.attribute_equality(Attribute::Class, &EntryClass::Recycled.into());
2038
2039 let extensible =
2042 self.attribute_equality(Attribute::Class, &EntryClass::ExtensibleObject.into());
2043
2044 let entry_classes = self.get_ava_set(Attribute::Class).ok_or_else(|| {
2045 admin_debug!("Attribute '{}' missing from entry", Attribute::Class);
2046 SchemaError::NoClassFound
2047 })?;
2048 let mut invalid_classes = Vec::with_capacity(0);
2049
2050 let mut classes: Vec<&SchemaClass> = Vec::with_capacity(entry_classes.len());
2051
2052 let entry_classes = if let Some(ec) = entry_classes.as_iutf8_set() {
2055 ec.iter()
2056 .for_each(|s| match schema_classes.get(s.as_str()) {
2057 Some(x) => classes.push(x),
2058 None => {
2059 admin_debug!("invalid class: {:?}", s);
2060 invalid_classes.push(s.to_string())
2061 }
2062 });
2063 ec
2064 } else {
2065 admin_debug!("corrupt class attribute");
2066 return Err(SchemaError::NoClassFound);
2067 };
2068
2069 if !invalid_classes.is_empty() {
2070 return Err(SchemaError::InvalidClass(invalid_classes));
2071 };
2072
2073 let supplements_classes: Vec<_> = classes
2077 .iter()
2078 .flat_map(|cls| cls.systemsupplements.iter().chain(cls.supplements.iter()))
2079 .collect();
2080
2081 let valid_supplements = if supplements_classes.is_empty() {
2083 true
2085 } else {
2086 supplements_classes
2087 .iter()
2088 .any(|class| entry_classes.contains(class.as_str()))
2089 };
2090
2091 if !valid_supplements {
2092 warn!(
2093 "Validation error, the following possible supplement classes are missing - {:?}",
2094 supplements_classes
2095 );
2096 let supplements_classes = supplements_classes.iter().map(|s| s.to_string()).collect();
2097 return Err(SchemaError::SupplementsNotSatisfied(supplements_classes));
2098 }
2099
2100 let excludes_classes: Vec<_> = classes
2101 .iter()
2102 .flat_map(|cls| cls.systemexcludes.iter().chain(cls.excludes.iter()))
2103 .collect();
2104
2105 let mut invalid_excludes = Vec::with_capacity(0);
2106
2107 excludes_classes.iter().for_each(|class| {
2108 if entry_classes.contains(class.as_str()) {
2109 invalid_excludes.push(class.to_string())
2110 }
2111 });
2112
2113 if !invalid_excludes.is_empty() {
2114 admin_warn!(
2115 "Validation error, the following excluded classes are present - {:?}",
2116 invalid_excludes
2117 );
2118 return Err(SchemaError::ExcludesNotSatisfied(invalid_excludes));
2119 }
2120
2121 let must: Result<Vec<&SchemaAttribute>, _> = classes
2134 .iter()
2135 .flat_map(|cls| cls.systemmust.iter().chain(cls.must.iter()))
2137 .map(|s| {
2138 schema_attributes.get(s).ok_or(SchemaError::Corrupted)
2141 })
2142 .collect();
2143
2144 let must = must?;
2145
2146 let mut missing_must = Vec::with_capacity(0);
2149 for attr in must.iter() {
2150 let avas = self.get_ava_set(&attr.name);
2151 if avas.is_none() {
2152 missing_must.push(attr.name.clone());
2153 }
2154 }
2155
2156 if !missing_must.is_empty() {
2157 admin_warn!(
2158 "Validation error, the following required ({}) (must) attributes are missing - {:?}",
2159 self.get_display_id(), missing_must
2160 );
2161 if !recycled {
2167 return Err(SchemaError::MissingMustAttribute(missing_must));
2168 }
2169 }
2170
2171 if extensible {
2172 self.attrs.iter().try_for_each(|(attr_name, avas)| {
2173 match schema_attributes.get(attr_name) {
2174 Some(a_schema) => {
2175 if a_schema.phantom {
2178 admin_warn!(
2179 "Rejecting attempt to add phantom attribute to extensible object: {}",
2180 attr_name
2181 );
2182 Err(SchemaError::PhantomAttribute(attr_name.to_string()))
2183 } else {
2184 a_schema.validate_ava(attr_name, avas)
2185 }
2187 }
2188 None => {
2189 admin_error!(
2190 "Invalid Attribute {}, undefined in schema_attributes",
2191 attr_name.to_string()
2192 );
2193 Err(SchemaError::InvalidAttribute(
2194 attr_name.to_string()
2195 ))
2196 }
2197 }
2198 })?;
2199 } else {
2200 let may: Result<Map<&Attribute, &SchemaAttribute>, _> = classes
2208 .iter()
2209 .flat_map(|cls| {
2211 trace!(?cls);
2212 cls.systemmust
2213 .iter()
2214 .chain(cls.must.iter())
2215 .chain(cls.systemmay.iter())
2216 .chain(cls.may.iter())
2217 })
2218 .map(|s| {
2219 Ok((s, schema_attributes.get(s).ok_or(SchemaError::Corrupted)?))
2222 })
2223 .collect();
2224
2225 let may = may?;
2226
2227 self.attrs.iter().try_for_each(|(attr_name, avas)| {
2236 match may.get(attr_name) {
2237 Some(a_schema) => {
2238 a_schema.validate_ava(attr_name, avas)
2241 }
2243 None => {
2244 admin_error!(
2245 "{} {} - not found in the list of valid attributes for this set of classes {:?} - valid attributes are {:?}",
2246
2247 attr_name.as_str(),
2248 self.get_display_id(),
2249 entry_classes.iter().collect::<Vec<_>>(),
2250 may.keys().collect::<Vec<_>>()
2251 );
2252 Err(SchemaError::AttributeNotValidForClass(
2253 attr_name.to_string()
2254 ))
2255 }
2256 }
2257 })?;
2258 }
2259
2260 Ok(())
2262 }
2263
2264 pub fn seal(mut self, schema: &dyn SchemaTransaction) -> Entry<EntrySealed, STATE> {
2265 let EntryValid { uuid, mut ecstate } = self.valid;
2266
2267 ecstate.retain(|k, _| schema.is_replicated(k));
2271
2272 let last_mod_cid = ecstate.get_max_cid();
2274 let cv = vs_cid![last_mod_cid.clone()];
2275 let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
2276
2277 let create_at_cid = ecstate.at();
2281 let cv = vs_cid![create_at_cid.clone()];
2282 let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
2283
2284 Entry {
2285 valid: EntrySealed { uuid, ecstate },
2286 state: self.state,
2287 attrs: self.attrs,
2288 }
2289 }
2290
2291 pub fn get_uuid(&self) -> Uuid {
2292 self.valid.uuid
2293 }
2294}
2295
2296impl<STATE> GetUuid for Entry<EntrySealed, STATE>
2297where
2298 STATE: Clone,
2299{
2300 fn get_uuid(&self) -> Uuid {
2301 self.valid.uuid
2302 }
2303}
2304
2305impl<STATE> Entry<EntrySealed, STATE>
2306where
2307 STATE: Clone,
2308{
2309 pub fn invalidate(mut self, cid: Cid, trim_cid: &Cid) -> Entry<EntryInvalid, STATE> {
2310 for vs in self.attrs.values_mut() {
2312 vs.trim(trim_cid);
2313 }
2314
2315 let last_mod_cid = self.valid.ecstate.get_max_cid();
2323 let cv = vs_cid![last_mod_cid.clone()];
2324 let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
2325
2326 let create_at_cid = self.valid.ecstate.at();
2327 let cv = vs_cid![create_at_cid.clone()];
2328 let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
2329
2330 Entry {
2331 valid: EntryInvalid {
2332 cid,
2333 ecstate: self.valid.ecstate,
2334 },
2335 state: self.state,
2336 attrs: self.attrs,
2337 }
2338 }
2339
2340 pub fn get_uuid(&self) -> Uuid {
2341 self.valid.uuid
2342 }
2343
2344 pub fn get_changestate(&self) -> &EntryChangeState {
2345 &self.valid.ecstate
2346 }
2347
2348 pub(crate) fn entry_changed_excluding_attribute<A: AsRef<Attribute>>(
2352 &self,
2353 attr: A,
2354 cid: &Cid,
2355 ) -> bool {
2356 let attr_ref = attr.as_ref();
2357
2358 use crate::repl::entry::State;
2359
2360 match self.get_changestate().current() {
2361 State::Live { at: _, changes } => {
2362 changes.iter().any(|(change_attr, change_id)| {
2363 change_id >= cid &&
2364 *change_attr != *attr_ref &&
2365 *change_attr != Attribute::LastModifiedCid
2367 })
2368 }
2369 State::Tombstone { at } => at == cid,
2370 }
2371 }
2372
2373 #[cfg(test)]
2377 pub(crate) fn into_invalid(mut self) -> Entry<EntryInvalid, STATE> {
2378 let cid = Cid::new_zero();
2379 self.set_last_changed(cid.clone());
2380
2381 let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
2382
2383 Entry {
2384 valid: EntryInvalid { cid, ecstate },
2385 state: self.state,
2386 attrs: self.attrs,
2387 }
2388 }
2389}
2390
2391impl GetUuid for Entry<EntryReduced, EntryCommitted> {
2392 fn get_uuid(&self) -> Uuid {
2393 self.valid.uuid
2394 }
2395}
2396
2397impl Entry<EntryReduced, EntryCommitted> {
2398 pub fn get_uuid(&self) -> Uuid {
2399 self.valid.uuid
2400 }
2401
2402 pub fn to_pe(&self, qs: &mut QueryServerReadTransaction) -> Result<ProtoEntry, OperationError> {
2404 let attrs: Result<_, _> = self
2406 .attrs
2407 .iter()
2408 .map(|(k, vs)| qs.resolve_valueset(vs).map(|pvs| (k.to_string(), pvs)))
2409 .collect();
2410 Ok(ProtoEntry { attrs: attrs? })
2411 }
2412
2413 pub fn to_scim_kanidm<'a, TXN>(
2414 &self,
2415 read_txn: &mut TXN,
2416 ) -> Result<ScimEntryKanidm, OperationError>
2417 where
2418 TXN: QueryServerTransaction<'a>,
2419 {
2420 let result: Result<BTreeMap<Attribute, ScimValueKanidm>, OperationError> = self
2421 .attrs
2422 .iter()
2423 .filter(|(k, _vs)| **k != Attribute::Uuid)
2425 .filter_map(|(k, vs)| {
2426 let opt_resolve_status = vs.to_scim_value();
2427 let res_opt_scim_value = match opt_resolve_status {
2428 None => Ok(None),
2429 Some(ScimResolveStatus::Resolved(scim_value_kani)) => Ok(Some(scim_value_kani)),
2430 Some(ScimResolveStatus::NeedsResolution(scim_value_interim)) => {
2431 read_txn.resolve_scim_interim(scim_value_interim)
2432 }
2433 };
2434 res_opt_scim_value
2435 .transpose()
2436 .map(|scim_res| scim_res.map(|scim_value| (k.clone(), scim_value)))
2437 })
2438 .collect();
2439
2440 let attrs = result?;
2441
2442 let ext_access_check = self.valid.effective_access.as_ref().map(|eff_acc| {
2443 let ident = eff_acc.ident;
2444 let delete = eff_acc.delete;
2445 let search = (&eff_acc.search).into();
2446 let modify_present = (&eff_acc.modify_pres).into();
2447 let modify_remove = (&eff_acc.modify_rem).into();
2448
2449 ScimEffectiveAccess {
2450 ident,
2451 delete,
2452 search,
2453 modify_present,
2454 modify_remove,
2455 }
2456 });
2457
2458 let id = self.get_uuid();
2459
2460 let schemas = Vec::with_capacity(0);
2463
2464 Ok(ScimEntryKanidm {
2465 header: ScimEntryHeader {
2466 schemas,
2467 id,
2468 external_id: None,
2470 meta: None,
2473 },
2474 ext_access_check,
2475 attrs,
2476 })
2477 }
2478
2479 pub fn to_ldap(
2481 &self,
2482 qs: &mut QueryServerReadTransaction,
2483 basedn: &str,
2484 all_attrs: bool,
2486 l_attrs: &[String],
2489 ) -> Result<LdapSearchResultEntry, OperationError> {
2490 let rdn = qs.uuid_to_rdn(self.get_uuid())?;
2491
2492 let dn = format!("{rdn},{basedn}");
2493
2494 let attr_map: Result<Map<&str, Vec<Vec<u8>>>, _> = self
2499 .attrs
2500 .iter()
2501 .map(|(k, vs)| {
2502 qs.resolve_valueset_ldap(vs, basedn)
2503 .map(|pvs| (k.as_str(), pvs))
2504 })
2505 .collect();
2506 let attr_map = attr_map?;
2507
2508 let attr_names: Vec<(&str, &str)> = if all_attrs {
2511 self.attrs
2513 .keys()
2514 .map(|k| (k.as_str(), k.as_str()))
2515 .chain(
2516 l_attrs
2517 .iter()
2518 .map(|k| (k.as_str(), ldap_vattr_map(k.as_str()).unwrap_or(k.as_str()))),
2519 )
2520 .collect()
2521 } else {
2522 l_attrs
2524 .iter()
2525 .map(|k| (k.as_str(), ldap_vattr_map(k.as_str()).unwrap_or(k.as_str())))
2526 .collect()
2527 };
2528
2529 let attributes: Vec<_> = attr_names
2531 .into_iter()
2532 .filter_map(|(ldap_a, kani_a)| {
2533 match ldap_a {
2535 LDAP_ATTR_DN => Some(LdapPartialAttribute {
2536 atype: LDAP_ATTR_DN.to_string(),
2537 vals: vec![dn.as_bytes().to_vec()],
2538 }),
2539 LDAP_ATTR_ENTRYDN => Some(LdapPartialAttribute {
2540 atype: LDAP_ATTR_ENTRYDN.to_string(),
2541 vals: vec![dn.as_bytes().to_vec()],
2542 }),
2543 LDAP_ATTR_MAIL_PRIMARY | LDAP_ATTR_EMAIL_PRIMARY => {
2544 attr_map.get(kani_a).map(|pvs| LdapPartialAttribute {
2545 atype: ldap_a.to_string(),
2546 vals: pvs
2547 .first()
2548 .map(|first| vec![first.clone()])
2549 .unwrap_or_default(),
2550 })
2551 }
2552 LDAP_ATTR_MAIL_ALTERNATIVE | LDAP_ATTR_EMAIL_ALTERNATIVE => {
2553 attr_map.get(kani_a).map(|pvs| LdapPartialAttribute {
2554 atype: ldap_a.to_string(),
2555 vals: pvs
2556 .split_first()
2557 .map(|(_, rest)| rest.to_vec())
2558 .unwrap_or_default(),
2559 })
2560 }
2561 ATTR_HOME_DIRECTORY => Some(LdapPartialAttribute {
2562 atype: ATTR_HOME_DIRECTORY.to_string(),
2563 vals: vec![format!("/home/{}", self.get_uuid()).into_bytes()],
2564 }),
2565 _ => attr_map.get(kani_a).map(|pvs| LdapPartialAttribute {
2566 atype: ldap_a.to_string(),
2567 vals: pvs.clone(),
2568 }),
2569 }
2570 })
2571 .collect();
2572
2573 Ok(LdapSearchResultEntry { dn, attributes })
2574 }
2575}
2576
2577impl<VALID, STATE> Entry<VALID, STATE> {
2579 fn add_ava_int(&mut self, attr: Attribute, value: Value) -> bool {
2584 if let Some(vs) = self.attrs.get_mut(&attr) {
2585 let r = vs.insert_checked(value);
2586 debug_assert!(r.is_ok());
2587 r.unwrap_or(false)
2589 } else {
2590 #[allow(clippy::expect_used)]
2591 let vs = valueset::from_value_iter(std::iter::once(value))
2592 .expect("Unable to fail - non-zero iter, and single value type!");
2593 self.attrs.insert(attr, vs);
2594 true
2596 }
2597 }
2599
2600 fn set_ava_iter_int<T>(&mut self, attr: Attribute, iter: T)
2602 where
2603 T: IntoIterator<Item = Value>,
2604 {
2605 let Ok(vs) = valueset::from_value_iter(iter.into_iter()) else {
2606 trace!("set_ava_iter_int - empty from_value_iter, skipping");
2607 return;
2608 };
2609
2610 if let Some(existing_vs) = self.attrs.get_mut(&attr) {
2611 let _ = existing_vs.merge(&vs);
2613 } else {
2614 self.attrs.insert(attr, vs);
2616 }
2617 }
2618
2619 #[cfg(test)]
2621 fn set_last_changed(&mut self, cid: Cid) {
2622 let cv = vs_cid![cid.clone()];
2623 let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
2624 let cv = vs_cid![cid];
2625 let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
2626 }
2627
2628 pub(crate) fn get_display_id(&self) -> String {
2629 self.attrs
2630 .get(&Attribute::Spn)
2631 .and_then(|vs| vs.to_value_single())
2632 .or_else(|| {
2633 self.attrs
2634 .get(&Attribute::Name)
2635 .and_then(|vs| vs.to_value_single())
2636 })
2637 .or_else(|| {
2638 self.attrs
2639 .get(&Attribute::Uuid)
2640 .and_then(|vs| vs.to_value_single())
2641 })
2642 .map(|value| value.to_proto_string_clone())
2643 .unwrap_or_else(|| "no entry id available".to_string())
2644 }
2645
2646 pub fn has_class(&self, class: &EntryClass) -> bool {
2647 self.get_ava_set(Attribute::Class)
2648 .and_then(|vs| vs.as_iutf8_set())
2649 .map(|set| {
2650 let class_name: &str = class.into();
2651 set.contains(class_name)
2652 })
2653 .unwrap_or_default()
2654 }
2655
2656 pub fn get_ava_names(&self) -> impl Iterator<Item = &str> {
2658 self.attrs.keys().map(|a| a.as_str())
2660 }
2661
2662 pub fn get_ava(&self) -> &Eattrs {
2664 &self.attrs
2665 }
2666
2667 pub fn get_ava_iter(&self) -> impl Iterator<Item = (&Attribute, &ValueSet)> {
2668 self.attrs.iter()
2669 }
2670
2671 pub fn get_ava_set<A: AsRef<Attribute>>(&self, attr: A) -> Option<&ValueSet> {
2673 self.attrs.get(attr.as_ref())
2674 }
2675
2676 pub fn get_ava_refer<A: AsRef<Attribute>>(&self, attr: A) -> Option<&BTreeSet<Uuid>> {
2677 self.get_ava_set(attr).and_then(|vs| vs.as_refer_set())
2678 }
2679
2680 pub fn get_ava_as_iutf8_iter<A: AsRef<Attribute>>(
2681 &self,
2682 attr: A,
2683 ) -> Option<impl Iterator<Item = &str>> {
2684 self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_iter())
2685 }
2686
2687 pub fn get_ava_as_iutf8<A: AsRef<Attribute>>(&self, attr: A) -> Option<&BTreeSet<String>> {
2688 self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_set())
2689 }
2690
2691 pub fn get_ava_as_image<A: AsRef<Attribute>>(&self, attr: A) -> Option<&HashSet<ImageValue>> {
2692 self.get_ava_set(attr).and_then(|vs| vs.as_imageset())
2693 }
2694
2695 pub fn get_ava_single_image<A: AsRef<Attribute>>(&self, attr: A) -> Option<ImageValue> {
2696 let images = self.get_ava_set(attr).and_then(|vs| vs.as_imageset())?;
2697 images.iter().next().cloned()
2698 }
2699
2700 pub fn get_ava_single_credential_type<A: AsRef<Attribute>>(
2701 &self,
2702 attr: A,
2703 ) -> Option<CredentialType> {
2704 self.get_ava_set(attr)
2705 .and_then(|vs| vs.to_credentialtype_single())
2706 }
2707
2708 pub fn get_ava_as_oauthscopes<A: AsRef<Attribute>>(
2709 &self,
2710 attr: A,
2711 ) -> Option<impl Iterator<Item = &str>> {
2712 self.get_ava_set(attr)
2713 .and_then(|vs| vs.as_oauthscope_iter())
2714 }
2715
2716 pub fn get_ava_as_oauthscopemaps<A: AsRef<Attribute>>(
2717 &self,
2718 attr: A,
2719 ) -> Option<&std::collections::BTreeMap<Uuid, std::collections::BTreeSet<String>>> {
2720 self.get_ava_set(attr).and_then(|vs| vs.as_oauthscopemap())
2721 }
2722
2723 pub fn get_ava_as_intenttokens<A: AsRef<Attribute>>(
2724 &self,
2725 attr: A,
2726 ) -> Option<&std::collections::BTreeMap<String, IntentTokenState>> {
2727 self.get_ava_set(attr)
2728 .and_then(|vs| vs.as_intenttoken_map())
2729 }
2730
2731 pub fn get_ava_as_session_map<A: AsRef<Attribute>>(
2732 &self,
2733 attr: A,
2734 ) -> Option<&std::collections::BTreeMap<Uuid, Session>> {
2735 self.get_ava_set(attr).and_then(|vs| vs.as_session_map())
2736 }
2737
2738 pub fn get_ava_as_apitoken_map<A: AsRef<Attribute>>(
2739 &self,
2740 attr: A,
2741 ) -> Option<&std::collections::BTreeMap<Uuid, ApiToken>> {
2742 self.get_ava_set(attr).and_then(|vs| vs.as_apitoken_map())
2743 }
2744
2745 pub fn get_ava_as_oauth2session_map<A: AsRef<Attribute>>(
2746 &self,
2747 attr: A,
2748 ) -> Option<&std::collections::BTreeMap<Uuid, Oauth2Session>> {
2749 self.get_ava_set(attr)
2750 .and_then(|vs| vs.as_oauth2session_map())
2751 }
2752
2753 pub fn get_ava_as_s256_set<A: AsRef<Attribute>>(
2754 &self,
2755 attr: A,
2756 ) -> Option<&std::collections::BTreeSet<Sha256Output>> {
2757 self.get_ava_set(attr).and_then(|vs| vs.as_s256_set())
2758 }
2759
2760 pub fn get_ava_iter_iname<A: AsRef<Attribute>>(
2762 &self,
2763 attr: A,
2764 ) -> Option<impl Iterator<Item = &str>> {
2765 self.get_ava_set(attr).and_then(|vs| vs.as_iname_iter())
2766 }
2767
2768 pub fn get_ava_iter_iutf8<A: AsRef<Attribute>>(
2770 &self,
2771 attr: A,
2772 ) -> Option<impl Iterator<Item = &str>> {
2773 self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_iter())
2774 }
2775
2776 pub fn get_ava_as_refuuid<A: AsRef<Attribute>>(
2778 &self,
2779 attr: A,
2780 ) -> Option<Box<dyn Iterator<Item = Uuid> + '_>> {
2781 self.get_ava_set(attr).and_then(|vs| vs.as_ref_uuid_iter())
2783 }
2784
2785 pub fn get_ava_iter_sshpubkeys<A: AsRef<Attribute>>(
2787 &self,
2788 attr: A,
2789 ) -> Option<impl Iterator<Item = String> + '_> {
2790 self.get_ava_set(attr)
2791 .and_then(|vs| vs.as_sshpubkey_string_iter())
2792 }
2793
2794 pub fn get_ava_single<A: AsRef<Attribute>>(&self, attr: A) -> Option<Value> {
2800 self.get_ava_set(attr).and_then(|vs| vs.to_value_single())
2801 }
2802
2803 pub fn get_ava_single_proto_string<A: AsRef<Attribute>>(&self, attr: A) -> Option<String> {
2804 self.get_ava_set(attr)
2805 .and_then(|vs| vs.to_proto_string_single())
2806 }
2807
2808 pub fn get_ava_single_bool<A: AsRef<Attribute>>(&self, attr: A) -> Option<bool> {
2810 self.get_ava_set(attr).and_then(|vs| vs.to_bool_single())
2811 }
2812
2813 pub fn get_ava_single_uint32<A: AsRef<Attribute>>(&self, attr: A) -> Option<u32> {
2815 self.get_ava_set(attr).and_then(|vs| vs.to_uint32_single())
2816 }
2817
2818 pub fn get_ava_single_syntax<A: AsRef<Attribute>>(&self, attr: A) -> Option<SyntaxType> {
2820 self.get_ava_set(attr)
2821 .and_then(|vs| vs.to_syntaxtype_single())
2822 }
2823
2824 pub fn get_ava_single_credential<A: AsRef<Attribute>>(&self, attr: A) -> Option<&Credential> {
2826 self.get_ava_set(attr)
2827 .and_then(|vs| vs.to_credential_single())
2828 }
2829
2830 pub fn get_ava_passkeys<A: AsRef<Attribute>>(
2832 &self,
2833 attr: A,
2834 ) -> Option<&BTreeMap<Uuid, (String, PasskeyV4)>> {
2835 self.get_ava_set(attr).and_then(|vs| vs.as_passkey_map())
2836 }
2837
2838 pub fn get_ava_attestedpasskeys<A: AsRef<Attribute>>(
2840 &self,
2841 attr: A,
2842 ) -> Option<&BTreeMap<Uuid, (String, AttestedPasskeyV4)>> {
2843 self.get_ava_set(attr)
2844 .and_then(|vs| vs.as_attestedpasskey_map())
2845 }
2846
2847 pub fn get_ava_uihint<A: AsRef<Attribute>>(&self, attr: A) -> Option<&BTreeSet<UiHint>> {
2849 self.get_ava_set(attr).and_then(|vs| vs.as_uihint_set())
2850 }
2851
2852 pub fn get_ava_single_secret<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2854 self.get_ava_set(attr).and_then(|vs| vs.to_secret_single())
2855 }
2856
2857 pub fn get_ava_single_datetime<A: AsRef<Attribute>>(&self, attr: A) -> Option<OffsetDateTime> {
2859 self.get_ava_set(attr)
2860 .and_then(|vs| vs.to_datetime_single())
2861 }
2862
2863 pub(crate) fn get_ava_single_utf8<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2865 self.get_ava_set(attr).and_then(|vs| vs.to_utf8_single())
2866 }
2867
2868 pub(crate) fn get_ava_single_iutf8<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2870 self.get_ava_set(attr).and_then(|vs| vs.to_iutf8_single())
2871 }
2872
2873 pub(crate) fn get_ava_single_iname<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2875 self.get_ava_set(attr).and_then(|vs| vs.to_iname_single())
2876 }
2877
2878 pub fn get_ava_single_url<A: AsRef<Attribute>>(&self, attr: A) -> Option<&Url> {
2880 self.get_ava_set(attr).and_then(|vs| vs.to_url_single())
2881 }
2882
2883 pub fn get_ava_single_uuid<A: AsRef<Attribute>>(&self, attr: A) -> Option<Uuid> {
2884 self.get_ava_set(attr).and_then(|vs| vs.to_uuid_single())
2885 }
2886
2887 pub fn get_ava_single_refer<A: AsRef<Attribute>>(&self, attr: A) -> Option<Uuid> {
2888 self.get_ava_set(attr).and_then(|vs| vs.to_refer_single())
2889 }
2890
2891 pub fn get_ava_mail_primary<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2892 self.get_ava_set(attr)
2893 .and_then(|vs| vs.to_email_address_primary_str())
2894 }
2895
2896 pub fn get_ava_iter_mail<A: AsRef<Attribute>>(
2897 &self,
2898 attr: A,
2899 ) -> Option<impl Iterator<Item = &str>> {
2900 self.get_ava_set(attr).and_then(|vs| vs.as_email_str_iter())
2901 }
2902
2903 pub fn get_ava_single_protofilter<A: AsRef<Attribute>>(&self, attr: A) -> Option<&ProtoFilter> {
2905 self.get_ava_set(attr)
2906 .and_then(|vs| vs.to_json_filter_single())
2907 }
2908
2909 pub fn get_ava_single_private_binary<A: AsRef<Attribute>>(&self, attr: A) -> Option<&[u8]> {
2910 self.get_ava_set(attr)
2911 .and_then(|vs| vs.to_private_binary_single())
2912 }
2913
2914 pub fn get_ava_single_jws_key_es256<A: AsRef<Attribute>>(
2915 &self,
2916 attr: A,
2917 ) -> Option<&JwsEs256Signer> {
2918 self.get_ava_set(attr)
2919 .and_then(|vs| vs.to_jws_key_es256_single())
2920 }
2921
2922 pub fn get_ava_single_eckey_private<A: AsRef<Attribute>>(
2923 &self,
2924 attr: A,
2925 ) -> Option<&EcKey<Private>> {
2926 self.get_ava_set(attr)
2927 .and_then(|vs| vs.to_eckey_private_single())
2928 }
2929
2930 pub fn get_ava_single_eckey_public<A: AsRef<Attribute>>(
2931 &self,
2932 attr: A,
2933 ) -> Option<&EcKey<Public>> {
2934 self.get_ava_set(attr)
2935 .and_then(|vs| vs.to_eckey_public_single())
2936 }
2937
2938 pub fn get_ava_webauthn_attestation_ca_list<A: AsRef<Attribute>>(
2939 &self,
2940 attr: A,
2941 ) -> Option<&AttestationCaList> {
2942 self.get_ava_set(attr)
2943 .and_then(|vs| vs.as_webauthn_attestation_ca_list())
2944 }
2945
2946 pub fn get_ava_application_password<A: AsRef<Attribute>>(
2947 &self,
2948 attr: A,
2949 ) -> Option<&BTreeMap<Uuid, Vec<ApplicationPassword>>> {
2950 self.get_ava_set(attr)
2951 .and_then(|vs| vs.as_application_password_map())
2952 }
2953
2954 pub(crate) fn generate_spn(&self, domain_name: &str) -> Option<ValueSet> {
2956 if let Some(name) = self.get_ava_single_iname(Attribute::Name) {
2957 return Some(ValueSetSpn::new((name.into(), domain_name.into())));
2959 }
2960
2961 let spn_set = self.get_ava_set(Attribute::Spn)?;
2963
2964 if spn_set.syntax() == SyntaxType::SecurityPrincipalName {
2965 Some(spn_set.clone())
2967 } else if let Some(name) = spn_set.to_iname_single() {
2968 Some(ValueSetSpn::new((name.into(), domain_name.into())))
2970 } else {
2971 None
2973 }
2974 }
2975
2976 pub fn attribute_pres<A: AsRef<Attribute>>(&self, attr: A) -> bool {
2978 self.attrs.contains_key(attr.as_ref())
2979 }
2980
2981 pub fn attribute_equality<A: AsRef<Attribute>>(&self, attr: A, value: &PartialValue) -> bool {
2984 match self.attrs.get(attr.as_ref()) {
2989 Some(v_list) => v_list.contains(value),
2990 None => false,
2991 }
2992 }
2993
2994 pub fn attribute_substring<A: AsRef<Attribute>>(
2997 &self,
2998 attr: A,
2999 subvalue: &PartialValue,
3000 ) -> bool {
3001 self.get_ava_set(attr)
3002 .map(|vset| vset.substring(subvalue))
3003 .unwrap_or(false)
3004 }
3005
3006 pub fn attribute_startswith<A: AsRef<Attribute>>(
3009 &self,
3010 attr: A,
3011 subvalue: &PartialValue,
3012 ) -> bool {
3013 self.get_ava_set(attr)
3014 .map(|vset| vset.startswith(subvalue))
3015 .unwrap_or(false)
3016 }
3017
3018 pub fn attribute_endswith<A: AsRef<Attribute>>(
3021 &self,
3022 attr: A,
3023 subvalue: &PartialValue,
3024 ) -> bool {
3025 self.get_ava_set(attr)
3026 .map(|vset| vset.endswith(subvalue))
3027 .unwrap_or(false)
3028 }
3029
3030 pub fn attribute_lessthan<A: AsRef<Attribute>>(
3033 &self,
3034 attr: A,
3035 subvalue: &PartialValue,
3036 ) -> bool {
3037 self.get_ava_set(attr)
3038 .map(|vset| vset.lessthan(subvalue))
3039 .unwrap_or(false)
3040 }
3041
3042 #[inline(always)]
3047 #[instrument(level = "trace", name = "entry::entry_match_no_index", skip(self))]
3048 pub fn entry_match_no_index(&self, filter: &Filter<FilterValidResolved>) -> bool {
3050 self.entry_match_no_index_inner(filter.to_inner())
3051 }
3052
3053 fn entry_match_no_index_inner(&self, filter: &FilterResolved) -> bool {
3057 match filter {
3060 FilterResolved::Eq(attr, value, _) => self.attribute_equality(attr, value),
3061 FilterResolved::Cnt(attr, subvalue, _) => self.attribute_substring(attr, subvalue),
3062 FilterResolved::Stw(attr, subvalue, _) => self.attribute_startswith(attr, subvalue),
3063 FilterResolved::Enw(attr, subvalue, _) => self.attribute_endswith(attr, subvalue),
3064 FilterResolved::Pres(attr, _) => self.attribute_pres(attr),
3065 FilterResolved::LessThan(attr, subvalue, _) => self.attribute_lessthan(attr, subvalue),
3066 FilterResolved::Or(l, _) => l.iter().any(|f| self.entry_match_no_index_inner(f)),
3068 FilterResolved::And(l, _) => l.iter().all(|f| self.entry_match_no_index_inner(f)),
3070 FilterResolved::Inclusion(_, _) => {
3071 false
3075 }
3076 FilterResolved::AndNot(f, _) => !self.entry_match_no_index_inner(f),
3077 FilterResolved::Invalid(_) => false,
3078 }
3079 }
3080
3081 pub fn filter_from_attrs(&self, attrs: &[Attribute]) -> Option<Filter<FilterInvalid>> {
3084 let mut pairs: Vec<(Attribute, PartialValue)> = Vec::with_capacity(0);
3096
3097 for attr in attrs {
3098 match self.attrs.get(attr) {
3099 Some(values) => values
3100 .to_partialvalue_iter()
3101 .for_each(|pv| pairs.push((attr.clone(), pv))),
3102 None => return None,
3103 }
3104 }
3105
3106 let res: Vec<FC> = pairs
3107 .into_iter()
3108 .map(|(attr, pv)| FC::Eq(attr, pv))
3109 .collect();
3110 Some(filter_all!(f_and(res)))
3111 }
3112
3113 pub fn gen_modlist_assert(
3116 &self,
3117 schema: &dyn SchemaTransaction,
3118 ) -> Result<ModifyList<ModifyInvalid>, SchemaError> {
3119 let mut mods = ModifyList::new();
3123
3124 for (k, vs) in self.attrs.iter() {
3125 if *k == Attribute::Uuid {
3141 continue;
3142 }
3143 match schema.is_multivalue(k) {
3145 Ok(r) => {
3146 if !r ||
3149 *k == Attribute::AcpReceiverGroup ||
3152 *k == Attribute::AcpCreateAttr ||
3153 *k == Attribute::AcpCreateClass ||
3154 *k == Attribute::AcpModifyPresentAttr ||
3155 *k == Attribute::AcpModifyRemovedAttr ||
3156 *k == Attribute::AcpModifyClass ||
3157 *k == Attribute::SystemMust ||
3158 *k == Attribute::SystemMay
3159 {
3160 mods.push_mod(Modify::Purged(k.clone()));
3161 }
3162 }
3163 Err(e) => return Err(e),
3165 }
3166 for v in vs.to_value_iter() {
3167 mods.push_mod(Modify::Present(k.clone(), v.clone()));
3168 }
3169 }
3170
3171 Ok(mods)
3172 }
3173
3174 pub fn mask_recycled_ts(&self) -> Option<&Self> {
3177 match self.attrs.get(&Attribute::Class) {
3179 Some(cls) => {
3180 if cls.contains(&EntryClass::Tombstone.to_partialvalue())
3181 || cls.contains(&EntryClass::Recycled.to_partialvalue())
3182 {
3183 None
3184 } else {
3185 Some(self)
3186 }
3187 }
3188 None => Some(self),
3189 }
3190 }
3191
3192 pub fn mask_recycled(&self) -> Option<&Self> {
3195 match self.attrs.get(&Attribute::Class) {
3197 Some(cls) => {
3198 if cls.contains(&EntryClass::Recycled.to_partialvalue()) {
3199 None
3200 } else {
3201 Some(self)
3202 }
3203 }
3204 None => Some(self),
3205 }
3206 }
3207
3208 pub fn mask_tombstone(&self) -> Option<&Self> {
3211 match self.attrs.get(&Attribute::Class) {
3213 Some(cls) => {
3214 if cls.contains(&EntryClass::Tombstone.to_partialvalue()) {
3215 None
3216 } else {
3217 Some(self)
3218 }
3219 }
3220 None => Some(self),
3221 }
3222 }
3223}
3224
3225impl<STATE> Entry<EntryInvalid, STATE>
3226where
3227 STATE: Clone,
3228{
3229 pub fn add_ava(&mut self, attr: Attribute, value: Value) {
3234 self.valid.ecstate.change_ava(&self.valid.cid, &attr);
3235 self.add_ava_int(attr, value);
3236 }
3237
3238 pub fn add_ava_if_not_exist<A: AsRef<Attribute>>(&mut self, attr: A, value: Value) {
3239 let attr_ref = attr.as_ref();
3240 if self.add_ava_int(attr_ref.clone(), value) {
3242 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3244 }
3245 }
3246
3247 fn assert_ava<A: AsRef<Attribute>>(
3248 &mut self,
3249 attr: A,
3250 value: &PartialValue,
3251 ) -> Result<(), OperationError> {
3252 self.valid
3253 .ecstate
3254 .change_ava(&self.valid.cid, attr.as_ref());
3255
3256 if self.attribute_equality(attr, value) {
3257 Ok(())
3258 } else {
3259 Err(OperationError::ModifyAssertionFailed)
3260 }
3261 }
3262
3263 pub(crate) fn remove_ava<A: AsRef<Attribute>>(&mut self, attr: A, value: &PartialValue) {
3266 let attr_ref = attr.as_ref();
3267 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3268
3269 let rm = if let Some(vs) = self.attrs.get_mut(attr_ref) {
3270 vs.remove(value, &self.valid.cid);
3271 vs.is_empty()
3272 } else {
3273 false
3274 };
3275 if rm {
3276 self.attrs.remove(attr_ref);
3277 };
3278 }
3279
3280 pub(crate) fn remove_avas<A: AsRef<Attribute>>(
3281 &mut self,
3282 attr: A,
3283 values: &BTreeSet<PartialValue>,
3284 ) {
3285 let attr_ref = attr.as_ref();
3286 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3287
3288 let rm = if let Some(vs) = self.attrs.get_mut(attr_ref) {
3289 values.iter().for_each(|k| {
3290 vs.remove(k, &self.valid.cid);
3291 });
3292 vs.is_empty()
3293 } else {
3294 false
3295 };
3296 if rm {
3297 self.attrs.remove(attr_ref);
3298 };
3299 }
3300
3301 pub(crate) fn purge_ava<A: AsRef<Attribute>>(&mut self, attr: A) {
3304 let attr_ref = attr.as_ref();
3305 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3306 let can_remove = self
3309 .attrs
3310 .get_mut(attr_ref)
3311 .map(|vs| vs.purge(&self.valid.cid))
3312 .unwrap_or_default();
3314 if can_remove {
3315 self.attrs.remove(attr_ref);
3316 }
3317 }
3318
3319 pub fn pop_ava<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<ValueSet> {
3321 let attr_ref = attr.as_ref();
3322 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3323
3324 let mut vs = self.attrs.remove(attr_ref)?;
3325 if vs.purge(&self.valid.cid) {
3326 Some(vs)
3328 } else {
3329 let r_vs = vs.clone();
3331 self.attrs.insert(attr_ref.clone(), vs);
3332 Some(r_vs)
3333 }
3334 }
3335
3336 #[cfg(test)]
3341 pub(crate) fn force_trim_ava<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<ValueSet> {
3342 self.valid
3343 .ecstate
3344 .change_ava(&self.valid.cid, attr.as_ref());
3345 self.attrs.remove(attr.as_ref())
3346 }
3347
3348 pub fn set_ava<T>(&mut self, attr: &Attribute, iter: T)
3351 where
3352 T: Clone + IntoIterator<Item = Value>,
3353 {
3354 self.purge_ava(attr);
3355 self.set_ava_iter_int(attr.clone(), iter)
3356 }
3357
3358 pub fn set_ava_set(&mut self, attr: &Attribute, vs: ValueSet) {
3361 self.purge_ava(attr);
3362 if let Some(existing_vs) = self.attrs.get_mut(attr) {
3363 let _ = existing_vs.merge(&vs);
3364 } else {
3365 self.attrs.insert(attr.clone(), vs);
3366 }
3367 }
3368
3369 pub fn merge_ava_set(&mut self, attr: &Attribute, vs: ValueSet) -> Result<(), OperationError> {
3372 self.valid.ecstate.change_ava(&self.valid.cid, attr);
3373 if let Some(existing_vs) = self.attrs.get_mut(attr) {
3374 existing_vs.merge(&vs)
3375 } else {
3376 self.attrs.insert(attr.clone(), vs);
3377 Ok(())
3378 }
3379 }
3380
3381 pub fn apply_modlist(
3383 &mut self,
3384 modlist: &ModifyList<ModifyValid>,
3385 ) -> Result<(), OperationError> {
3386 for modify in modlist {
3387 match modify {
3388 Modify::Present(attr, value) => {
3389 self.add_ava(attr.clone(), value.clone());
3390 }
3391 Modify::Removed(attr, value) => {
3392 self.remove_ava(attr, value);
3393 }
3394 Modify::Purged(attr) => {
3395 self.purge_ava(attr);
3396 }
3397 Modify::Assert(attr, value) => {
3398 self.assert_ava(attr, value).inspect_err(|_e| {
3399 error!("Modification assertion was not met. {} {:?}", attr, value);
3400 })?;
3401 }
3402 Modify::Set(attr, valueset) => self.set_ava_set(attr, valueset.clone()),
3403 }
3404 }
3405 Ok(())
3406 }
3407}
3408
3409impl<VALID, STATE> PartialEq for Entry<VALID, STATE> {
3410 fn eq(&self, rhs: &Entry<VALID, STATE>) -> bool {
3411 compare_attrs(&self.attrs, &rhs.attrs)
3422 }
3423}
3424
3425#[cfg(test)]
3426mod tests {
3427 use crate::prelude::*;
3428 use std::collections::BTreeSet as Set;
3429
3430 use hashbrown::HashMap;
3431
3432 use crate::be::{IdxKey, IdxSlope};
3433 use crate::entry::{Entry, EntryInit, EntryInvalid, EntryNew};
3434 use crate::modify::{Modify, ModifyList};
3435 use crate::value::{IndexType, PartialValue, Value};
3436
3437 #[test]
3438 fn test_entry_basic() {
3439 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3440
3441 e.add_ava(Attribute::UserId, Value::from("william"));
3442 }
3443
3444 #[test]
3445 fn test_entry_dup_value() {
3446 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3453 e.add_ava(Attribute::UserId, Value::from("william"));
3454 e.add_ava(Attribute::UserId, Value::from("william"));
3455
3456 let values = e.get_ava_set(Attribute::UserId).expect("Failed to get ava");
3457 assert_eq!(values.len(), 1)
3459 }
3460
3461 #[test]
3462 fn test_entry_pres() {
3463 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3464 e.add_ava(Attribute::UserId, Value::from("william"));
3465
3466 assert!(e.attribute_pres(Attribute::UserId));
3467 assert!(!e.attribute_pres(Attribute::Name));
3468 }
3469
3470 #[test]
3471 fn test_entry_equality() {
3472 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3473
3474 e.add_ava(Attribute::UserId, Value::from("william"));
3475
3476 assert!(e.attribute_equality(Attribute::UserId, &PartialValue::new_utf8s("william")));
3477 assert!(!e.attribute_equality(Attribute::UserId, &PartialValue::new_utf8s("test")));
3478 assert!(!e.attribute_equality(Attribute::NonExist, &PartialValue::new_utf8s("william")));
3479 assert!(!e.attribute_equality(Attribute::UserId, &PartialValue::new_iutf8("william")));
3481 }
3482
3483 #[test]
3484 fn test_entry_substring() {
3485 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3486
3487 e.add_ava(Attribute::UserId, Value::from("william"));
3488
3489 assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("william")));
3490 assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("will")));
3491 assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("liam")));
3492 assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("lli")));
3493 assert!(!e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("llim")));
3494 assert!(!e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("bob")));
3495 assert!(!e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("wl")));
3496
3497 assert!(e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("will")));
3498 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("liam")));
3499 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("lli")));
3500 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("llim")));
3501 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("bob")));
3502 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("wl")));
3503
3504 assert!(e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("liam")));
3505 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("will")));
3506 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("lli")));
3507 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("llim")));
3508 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("bob")));
3509 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("wl")));
3510 }
3511
3512 #[test]
3513 fn test_entry_lessthan() {
3514 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3515
3516 let pv2 = PartialValue::new_uint32(2);
3517 let pv8 = PartialValue::new_uint32(8);
3518 let pv10 = PartialValue::new_uint32(10);
3519 let pv15 = PartialValue::new_uint32(15);
3520
3521 e1.add_ava(Attribute::TestAttr, Value::new_uint32(10));
3522
3523 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv2));
3524 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv8));
3525 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv10));
3526 assert!(e1.attribute_lessthan(Attribute::TestAttr, &pv15));
3527
3528 e1.add_ava(Attribute::TestAttr, Value::new_uint32(8));
3529
3530 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv2));
3531 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv8));
3532 assert!(e1.attribute_lessthan(Attribute::TestAttr, &pv10));
3533 assert!(e1.attribute_lessthan(Attribute::TestAttr, &pv15));
3534 }
3535
3536 #[test]
3537 fn test_entry_apply_modlist() {
3538 let mut e: Entry<EntryInvalid, EntryNew> = Entry::new().into_invalid_new();
3540
3541 e.add_ava(Attribute::UserId, Value::from("william"));
3542
3543 let present_single_mods = ModifyList::new_valid_list(vec![Modify::Present(
3544 Attribute::Attr,
3545 Value::new_iutf8("value"),
3546 )]);
3547
3548 assert!(e.apply_modlist(&present_single_mods).is_ok());
3549
3550 assert!(e.attribute_equality(Attribute::UserId, &PartialValue::new_utf8s("william")));
3552 assert!(e.attribute_equality(Attribute::Attr, &PartialValue::new_iutf8("value")));
3553
3554 let present_multivalue_mods = ModifyList::new_valid_list(vec![
3556 Modify::Present(Attribute::Class, Value::new_iutf8("test")),
3557 Modify::Present(Attribute::Class, Value::new_iutf8("multi_test")),
3558 ]);
3559
3560 assert!(e.apply_modlist(&present_multivalue_mods).is_ok());
3561
3562 assert!(e.attribute_equality(Attribute::Class, &PartialValue::new_iutf8("test")));
3563 assert!(e.attribute_equality(Attribute::Class, &PartialValue::new_iutf8("multi_test")));
3564
3565 let purge_single_mods = ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Attr)]);
3567
3568 assert!(e.apply_modlist(&purge_single_mods).is_ok());
3569
3570 assert!(!e.attribute_pres(Attribute::Attr));
3571
3572 let purge_multi_mods = ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Class)]);
3573
3574 assert!(e.apply_modlist(&purge_multi_mods).is_ok());
3575
3576 assert!(!e.attribute_pres(Attribute::Class));
3577
3578 let purge_empty_mods = purge_single_mods;
3579
3580 assert!(e.apply_modlist(&purge_empty_mods).is_ok());
3581
3582 let remove_mods = ModifyList::new_valid_list(vec![Modify::Removed(
3584 Attribute::Attr,
3585 PartialValue::new_iutf8("value"),
3586 )]);
3587
3588 assert!(e.apply_modlist(&present_single_mods).is_ok());
3589 assert!(e.attribute_equality(Attribute::Attr, &PartialValue::new_iutf8("value")));
3590 assert!(e.apply_modlist(&remove_mods).is_ok());
3591 assert!(!e.attrs.contains_key(&Attribute::Attr));
3592
3593 let remove_empty_mods = remove_mods;
3594
3595 assert!(e.apply_modlist(&remove_empty_mods).is_ok());
3596
3597 assert!(!e.attrs.contains_key(&Attribute::Attr));
3598 }
3599
3600 #[test]
3601 fn test_entry_idx_diff() {
3602 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3603 e1.add_ava(Attribute::UserId, Value::from("william"));
3604 let mut e1_mod = e1.clone();
3605 e1_mod.add_ava(Attribute::Extra, Value::from("test"));
3606
3607 let e1 = e1.into_sealed_committed();
3608 let e1_mod = e1_mod.into_sealed_committed();
3609
3610 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3611 e2.add_ava(Attribute::UserId, Value::from("claire"));
3612 let e2 = e2.into_sealed_committed();
3613
3614 let mut idxmeta = HashMap::with_capacity(8);
3615 idxmeta.insert(
3616 IdxKey {
3617 attr: Attribute::UserId,
3618 itype: IndexType::Equality,
3619 },
3620 IdxSlope::MAX,
3621 );
3622 idxmeta.insert(
3623 IdxKey {
3624 attr: Attribute::UserId,
3625 itype: IndexType::Presence,
3626 },
3627 IdxSlope::MAX,
3628 );
3629 idxmeta.insert(
3630 IdxKey {
3631 attr: Attribute::Extra,
3632 itype: IndexType::Equality,
3633 },
3634 IdxSlope::MAX,
3635 );
3636
3637 let r1 = Entry::idx_diff(&idxmeta, None, None);
3639 eprintln!("{r1:?}");
3640 assert_eq!(r1, Vec::with_capacity(0));
3641
3642 let mut del_r = Entry::idx_diff(&idxmeta, Some(&e1), None);
3644 del_r.sort_unstable();
3645 eprintln!("del_r {del_r:?}");
3646 assert!(
3647 del_r[0]
3648 == Err((
3649 &Attribute::UserId,
3650 IndexType::Equality,
3651 "william".to_string()
3652 ))
3653 );
3654 assert!(del_r[1] == Err((&Attribute::UserId, IndexType::Presence, "_".to_string())));
3655
3656 let mut add_r = Entry::idx_diff(&idxmeta, None, Some(&e1));
3658 add_r.sort_unstable();
3659 eprintln!("{add_r:?}");
3660 assert!(
3661 add_r[0]
3662 == Ok((
3663 &Attribute::UserId,
3664 IndexType::Equality,
3665 "william".to_string()
3666 ))
3667 );
3668 assert!(add_r[1] == Ok((&Attribute::UserId, IndexType::Presence, "_".to_string())));
3669
3670 let no_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e1));
3674 assert!(no_r.is_empty());
3675
3676 let add_a_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e1_mod));
3678 assert!(add_a_r[0] == Ok((&Attribute::Extra, IndexType::Equality, "test".to_string())));
3679
3680 let del_a_r = Entry::idx_diff(&idxmeta, Some(&e1_mod), Some(&e1));
3682 assert!(del_a_r[0] == Err((&Attribute::Extra, IndexType::Equality, "test".to_string())));
3683
3684 let mut chg_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e2));
3686 chg_r.sort_unstable();
3687 eprintln!("{chg_r:?}");
3688 assert!(
3689 chg_r[1]
3690 == Err((
3691 &Attribute::UserId,
3692 IndexType::Equality,
3693 "william".to_string()
3694 ))
3695 );
3696
3697 assert!(
3698 chg_r[0]
3699 == Ok((
3700 &Attribute::UserId,
3701 IndexType::Equality,
3702 "claire".to_string()
3703 ))
3704 );
3705 }
3706
3707 #[test]
3708 fn test_entry_mask_recycled_ts() {
3709 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3710 e1.add_ava(Attribute::Class, EntryClass::Person.to_value());
3711 let e1 = e1.into_sealed_committed();
3712 assert!(e1.mask_recycled_ts().is_some());
3713
3714 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3715 e2.add_ava(Attribute::Class, EntryClass::Person.to_value());
3716 e2.add_ava(Attribute::Class, EntryClass::Recycled.into());
3717 let e2 = e2.into_sealed_committed();
3718 assert!(e2.mask_recycled_ts().is_none());
3719
3720 let mut e3: Entry<EntryInit, EntryNew> = Entry::new();
3721 e3.add_ava(Attribute::Class, EntryClass::Tombstone.into());
3722 let e3 = e3.into_sealed_committed();
3723 assert!(e3.mask_recycled_ts().is_none());
3724 }
3725
3726 #[test]
3727 fn test_entry_idx_name2uuid_diff() {
3728 let r = Entry::idx_name2uuid_diff(None, None);
3730 assert_eq!(r, (None, None));
3731
3732 {
3734 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3735 e.add_ava(Attribute::Class, EntryClass::Person.to_value());
3736 let e = e.into_sealed_committed();
3737
3738 assert!(Entry::idx_name2uuid_diff(None, Some(&e)) == (Some(Set::new()), None));
3739 }
3740
3741 {
3742 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3743 e.add_ava(Attribute::Class, EntryClass::Person.to_value());
3744 e.add_ava(Attribute::GidNumber, Value::new_uint32(1300));
3745 e.add_ava(Attribute::Name, Value::new_iname("testperson"));
3746 e.add_ava(
3747 Attribute::Spn,
3748 Value::new_spn_str("testperson", "example.com"),
3749 );
3750 e.add_ava(
3751 Attribute::Uuid,
3752 Value::Uuid(uuid!("9fec0398-c46c-4df4-9df5-b0016f7d563f")),
3753 );
3754 let e = e.into_sealed_committed();
3755
3756 assert!(
3758 Entry::idx_name2uuid_diff(None, Some(&e))
3759 == (
3760 Some(btreeset![
3761 "1300".to_string(),
3762 "testperson".to_string(),
3763 "testperson@example.com".to_string()
3764 ]),
3765 None
3766 )
3767 );
3768 assert!(
3771 Entry::idx_name2uuid_diff(Some(&e), None)
3772 == (
3773 None,
3774 Some(btreeset![
3775 "1300".to_string(),
3776 "testperson".to_string(),
3777 "testperson@example.com".to_string()
3778 ])
3779 )
3780 );
3781
3782 assert!(
3784 Entry::idx_name2uuid_diff(Some(&e), Some(&e))
3785 == (Some(Set::new()), Some(Set::new()))
3786 );
3787 }
3788 {
3791 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3792 e1.add_ava(Attribute::Class, EntryClass::Person.to_value());
3793 e1.add_ava(
3794 Attribute::Spn,
3795 Value::new_spn_str("testperson", "example.com"),
3796 );
3797 let e1 = e1.into_sealed_committed();
3798
3799 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3800 e2.add_ava(Attribute::Class, EntryClass::Person.to_value());
3801 e2.add_ava(Attribute::Name, Value::new_iname("testperson"));
3802 e2.add_ava(
3803 Attribute::Spn,
3804 Value::new_spn_str("testperson", "example.com"),
3805 );
3806 let e2 = e2.into_sealed_committed();
3807
3808 assert!(
3810 Entry::idx_name2uuid_diff(Some(&e1), Some(&e2))
3811 == (Some(btreeset!["testperson".to_string()]), Some(Set::new()))
3812 );
3813
3814 assert!(
3816 Entry::idx_name2uuid_diff(Some(&e2), Some(&e1))
3817 == (Some(Set::new()), Some(btreeset!["testperson".to_string()]))
3818 );
3819 }
3820
3821 {
3823 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3824 e1.add_ava(Attribute::Class, EntryClass::Person.to_value());
3825 e1.add_ava(
3826 Attribute::Spn,
3827 Value::new_spn_str("testperson", "example.com"),
3828 );
3829 let e1 = e1.into_sealed_committed();
3830
3831 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3832 e2.add_ava(Attribute::Class, EntryClass::Person.to_value());
3833 e2.add_ava(
3834 Attribute::Spn,
3835 Value::new_spn_str("renameperson", "example.com"),
3836 );
3837 let e2 = e2.into_sealed_committed();
3838
3839 assert!(
3840 Entry::idx_name2uuid_diff(Some(&e1), Some(&e2))
3841 == (
3842 Some(btreeset!["renameperson@example.com".to_string()]),
3843 Some(btreeset!["testperson@example.com".to_string()])
3844 )
3845 );
3846 }
3847 }
3848
3849 #[test]
3850 fn test_entry_idx_uuid2spn_diff() {
3851 assert!(Entry::idx_uuid2spn_diff(None, None).is_none());
3852
3853 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3854 e1.add_ava(
3855 Attribute::Spn,
3856 Value::new_spn_str("testperson", "example.com"),
3857 );
3858 let e1 = e1.into_sealed_committed();
3859
3860 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3861 e2.add_ava(
3862 Attribute::Spn,
3863 Value::new_spn_str("renameperson", "example.com"),
3864 );
3865 let e2 = e2.into_sealed_committed();
3866
3867 assert!(
3868 Entry::idx_uuid2spn_diff(None, Some(&e1))
3869 == Some(Ok(Value::new_spn_str("testperson", "example.com")))
3870 );
3871 assert!(Entry::idx_uuid2spn_diff(Some(&e1), None) == Some(Err(())));
3872 assert!(Entry::idx_uuid2spn_diff(Some(&e1), Some(&e1)).is_none());
3873 assert!(
3874 Entry::idx_uuid2spn_diff(Some(&e1), Some(&e2))
3875 == Some(Ok(Value::new_spn_str("renameperson", "example.com")))
3876 );
3877 }
3878
3879 #[test]
3880 fn test_entry_idx_uuid2rdn_diff() {
3881 assert!(Entry::idx_uuid2rdn_diff(None, None).is_none());
3882
3883 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3884 e1.add_ava(
3885 Attribute::Spn,
3886 Value::new_spn_str("testperson", "example.com"),
3887 );
3888 let e1 = e1.into_sealed_committed();
3889
3890 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3891 e2.add_ava(
3892 Attribute::Spn,
3893 Value::new_spn_str("renameperson", "example.com"),
3894 );
3895 let e2 = e2.into_sealed_committed();
3896
3897 assert!(
3898 Entry::idx_uuid2rdn_diff(None, Some(&e1))
3899 == Some(Ok("spn=testperson@example.com".to_string()))
3900 );
3901 assert!(Entry::idx_uuid2rdn_diff(Some(&e1), None) == Some(Err(())));
3902 assert!(Entry::idx_uuid2rdn_diff(Some(&e1), Some(&e1)).is_none());
3903 assert!(
3904 Entry::idx_uuid2rdn_diff(Some(&e1), Some(&e2))
3905 == Some(Ok("spn=renameperson@example.com".to_string()))
3906 );
3907 }
3908}