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 pop_ava<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<ValueSet> {
489 self.attrs.remove(attr.as_ref())
490 }
491
492 pub fn remove_ava<A: AsRef<Attribute>>(&mut self, attr: A) {
493 self.pop_ava(attr);
494 }
495
496 pub fn set_ava_set(&mut self, attr: &Attribute, vs: ValueSet) {
498 self.attrs.insert(attr.clone(), vs);
499 }
500
501 pub fn set_ava<T>(&mut self, attr: Attribute, iter: T)
503 where
504 T: IntoIterator<Item = Value>,
505 {
506 self.set_ava_iter_int(attr, iter);
507 }
508
509 pub fn get_ava_mut<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<&mut ValueSet> {
510 self.attrs.get_mut(attr.as_ref())
511 }
512}
513
514impl From<SchemaAttribute> for EntryInitNew {
515 fn from(value: SchemaAttribute) -> Self {
516 EntryInitNew::from(&value)
517 }
518}
519
520impl From<&SchemaAttribute> for EntryInitNew {
521 fn from(s: &SchemaAttribute) -> Self {
522 let mut attrs = Eattrs::new();
524 attrs.insert(Attribute::AttributeName, vs_iutf8![s.name.as_str()]);
525 attrs.insert(Attribute::Description, vs_utf8![s.description.to_owned()]);
526 attrs.insert(Attribute::Uuid, vs_uuid![s.uuid]);
527 attrs.insert(Attribute::MultiValue, vs_bool![s.multivalue]);
528 attrs.insert(Attribute::Phantom, vs_bool![s.phantom]);
529 attrs.insert(Attribute::SyncAllowed, vs_bool![s.sync_allowed]);
530 attrs.insert(Attribute::Replicated, vs_bool![s.replicated.into()]);
531 attrs.insert(Attribute::Unique, vs_bool![s.unique]);
532 attrs.insert(Attribute::Indexed, vs_bool![s.indexed]);
533 attrs.insert(Attribute::Syntax, vs_syntax![s.syntax]);
534 attrs.insert(
535 Attribute::Class,
536 vs_iutf8![
537 EntryClass::Object.into(),
538 EntryClass::System.into(),
539 EntryClass::AttributeType.into()
540 ],
541 );
542
543 Entry {
546 valid: EntryInit,
547 state: EntryNew,
548 attrs,
549 }
550 }
551}
552
553impl From<SchemaClass> for EntryInitNew {
554 fn from(value: SchemaClass) -> Self {
555 EntryInitNew::from(&value)
556 }
557}
558
559impl From<&SchemaClass> for EntryInitNew {
560 fn from(s: &SchemaClass) -> Self {
561 let mut attrs = Eattrs::new();
562 attrs.insert(Attribute::ClassName, vs_iutf8![s.name.as_str()]);
563 attrs.insert(Attribute::Description, vs_utf8![s.description.to_owned()]);
564 attrs.insert(Attribute::SyncAllowed, vs_bool![s.sync_allowed]);
565 attrs.insert(Attribute::Uuid, vs_uuid![s.uuid]);
566 attrs.insert(
567 Attribute::Class,
568 vs_iutf8![
569 EntryClass::Object.into(),
570 EntryClass::System.into(),
571 EntryClass::ClassType.into()
572 ],
573 );
574
575 let vs_systemmay = ValueSetIutf8::from_iter(s.systemmay.iter().map(|sm| sm.as_str()));
576 if let Some(vs) = vs_systemmay {
577 attrs.insert(Attribute::SystemMay, vs);
578 }
579
580 let vs_systemmust = ValueSetIutf8::from_iter(s.systemmust.iter().map(|sm| sm.as_str()));
581 if let Some(vs) = vs_systemmust {
582 attrs.insert(Attribute::SystemMust, vs);
583 }
584
585 let vs_systemexcludes =
586 ValueSetIutf8::from_iter(s.systemexcludes.iter().map(|sm| sm.as_str()));
587 if let Some(vs) = vs_systemexcludes {
588 attrs.insert(Attribute::SystemExcludes, vs);
589 }
590
591 let vs_systemsupplements =
592 ValueSetIutf8::from_iter(s.systemsupplements.iter().map(|sm| sm.as_str()));
593 if let Some(vs) = vs_systemsupplements {
594 attrs.insert(Attribute::SystemSupplements, vs);
595 }
596
597 Entry {
598 valid: EntryInit,
599 state: EntryNew,
600 attrs,
601 }
602 }
603}
604
605impl Entry<EntryRefresh, EntryNew> {
606 pub fn from_repl_entry_v1(repl_entry: ReplEntryV1) -> Result<Self, OperationError> {
607 let (ecstate, mut attrs) = repl_entry.rehydrate()?;
609
610 let last_mod_cid = ecstate.get_max_cid();
613 let cv = vs_cid![last_mod_cid.clone()];
614 let _ = attrs.insert(Attribute::LastModifiedCid, cv);
615
616 let create_at_cid = ecstate.at();
617 let cv = vs_cid![create_at_cid.clone()];
618 let _ = attrs.insert(Attribute::CreatedAtCid, cv);
619
620 Ok(Entry {
621 valid: EntryRefresh { ecstate },
622 state: EntryNew,
623 attrs,
624 })
625 }
626}
627
628impl<STATE> Entry<EntryRefresh, STATE> {
629 pub fn validate(
630 self,
631 schema: &dyn SchemaTransaction,
632 ) -> Result<Entry<EntryValid, STATE>, SchemaError> {
633 let uuid: Uuid = self
634 .attrs
635 .get(&Attribute::Uuid)
636 .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
637 .and_then(|vs| {
638 vs.to_uuid_single()
639 .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
640 })?;
641
642 let ne = Entry {
644 valid: EntryValid {
645 uuid,
646 ecstate: self.valid.ecstate,
647 },
648 state: self.state,
649 attrs: self.attrs,
650 };
651
652 ne.validate(schema).map(|()| ne)
653 }
654}
655
656impl<STATE> Entry<EntryIncremental, STATE> {
657 pub fn get_uuid(&self) -> Uuid {
658 self.valid.uuid
659 }
660}
661
662impl Entry<EntryIncremental, EntryNew> {
663 fn stub_ecstate(&self) -> EntryChangeState {
664 self.valid.ecstate.stub()
665 }
666
667 pub fn rehydrate(repl_inc_entry: ReplIncrementalEntryV1) -> Result<Self, OperationError> {
668 let (uuid, ecstate, attrs) = repl_inc_entry.rehydrate()?;
669
670 Ok(Entry {
671 valid: EntryIncremental { uuid, ecstate },
672 state: EntryNew,
673 attrs,
674 })
675 }
676
677 pub(crate) fn is_add_conflict(&self, db_entry: &EntrySealedCommitted) -> bool {
678 use crate::repl::entry::State;
679 debug_assert_eq!(self.valid.uuid, db_entry.valid.uuid);
680 let self_cs = &self.valid.ecstate;
682 let db_cs = db_entry.get_changestate();
683
684 match (self_cs.current(), db_cs.current()) {
686 (State::Live { at: at_left, .. }, State::Live { at: at_right, .. }) => {
687 at_left != at_right
688 }
689 _ => false,
691 }
692 }
693
694 pub(crate) fn resolve_add_conflict(
695 &self,
696 cid: &Cid,
697 db_ent: &EntrySealedCommitted,
698 ) -> (Option<EntrySealedNew>, EntryIncrementalCommitted) {
699 use crate::repl::entry::State;
700 debug_assert_eq!(self.valid.uuid, db_ent.valid.uuid);
701 let self_cs = &self.valid.ecstate;
702 let db_cs = db_ent.get_changestate();
703
704 match (self_cs.current(), db_cs.current()) {
705 (
706 State::Live {
707 at: at_left,
708 changes: _changes_left,
709 },
710 State::Live {
711 at: at_right,
712 changes: _changes_right,
713 },
714 ) => {
715 debug_assert!(at_left != at_right);
716 if at_left > at_right {
727 trace!("RI > DE, return DE");
728 (
729 None,
730 Entry {
731 valid: EntryIncremental {
732 uuid: db_ent.valid.uuid,
733 ecstate: db_cs.clone(),
734 },
735 state: EntryCommitted {
736 id: db_ent.state.id,
737 },
738 attrs: db_ent.attrs.clone(),
739 },
740 )
741 }
742 else {
752 trace!("RI < DE, return RI");
753 let conflict = if at_right.s_uuid == cid.s_uuid {
755 trace!("Origin process conflict entry");
756 let mut cnf_ent = Entry {
759 valid: EntryInvalid {
760 cid: cid.clone(),
761 ecstate: db_cs.clone(),
762 },
763 state: EntryNew,
764 attrs: db_ent.attrs.clone(),
765 };
766
767 cnf_ent.add_ava(Attribute::SourceUuid, Value::Uuid(db_ent.valid.uuid));
769
770 let new_uuid = Uuid::new_v4();
772 cnf_ent.purge_ava(Attribute::Uuid);
773 cnf_ent.add_ava(Attribute::Uuid, Value::Uuid(new_uuid));
774 cnf_ent.add_ava(Attribute::Class, EntryClass::Recycled.into());
775 cnf_ent.add_ava(Attribute::Class, EntryClass::Conflict.into());
776
777 let cv = vs_cid![cid.clone()];
781 let _ = cnf_ent.attrs.insert(Attribute::LastModifiedCid, cv);
782 let cv = vs_cid![cid.clone()];
784 let _ = cnf_ent.attrs.insert(Attribute::CreatedAtCid, cv);
785
786 let Entry {
790 valid: EntryInvalid { cid: _, ecstate },
791 state,
792 attrs,
793 } = cnf_ent;
794
795 let cnf_ent = Entry {
796 valid: EntrySealed {
797 uuid: new_uuid,
798 ecstate,
799 },
800 state,
801 attrs,
802 };
803
804 Some(cnf_ent)
805 } else {
806 None
807 };
808
809 let mut attrs = self.attrs.clone();
813 let ecstate = self_cs.clone();
814
815 let last_mod_cid = ecstate.get_max_cid();
816 let cv = vs_cid![last_mod_cid.clone()];
817 let _ = attrs.insert(Attribute::LastModifiedCid, cv);
818
819 let create_at_cid = ecstate.at();
820 let cv = vs_cid![create_at_cid.clone()];
821 let _ = attrs.insert(Attribute::CreatedAtCid, cv);
822
823 (
824 conflict,
825 Entry {
826 valid: EntryIncremental {
827 uuid: self.valid.uuid,
828 ecstate,
829 },
830 state: EntryCommitted {
831 id: db_ent.state.id,
832 },
833 attrs,
834 },
835 )
836 }
837 }
838 _ => unreachable!(),
842 }
843 }
844
845 pub(crate) fn merge_state(
846 &self,
847 db_ent: &EntrySealedCommitted,
848 schema: &dyn SchemaTransaction,
849 trim_cid: &Cid,
850 ) -> EntryIncrementalCommitted {
851 use crate::repl::entry::State;
852
853 debug_assert_eq!(self.valid.uuid, db_ent.valid.uuid);
855
856 let self_cs = &self.valid.ecstate;
859 let db_cs = db_ent.get_changestate();
860
861 match (self_cs.current(), db_cs.current()) {
862 (
863 State::Live {
864 at: at_left,
865 changes: changes_left,
866 },
867 State::Live {
868 at: at_right,
869 changes: changes_right,
870 },
871 ) => {
872 debug_assert_eq!(at_left, at_right);
873 let mut attr_set: Vec<_> =
878 changes_left.keys().chain(changes_right.keys()).collect();
879 attr_set.shrink_to_fit();
880 attr_set.sort_unstable();
881 attr_set.dedup();
882
883 let mut changes = BTreeMap::default();
885 let mut eattrs = Eattrs::default();
886
887 for attr_name in attr_set.into_iter() {
889 match (changes_left.get(attr_name), changes_right.get(attr_name)) {
890 (Some(cid_left), Some(cid_right)) => {
891 let take_left = cid_left > cid_right;
898
899 match (self.attrs.get(attr_name), db_ent.attrs.get(attr_name)) {
900 (Some(vs_left), Some(vs_right)) if take_left => {
901 changes.insert(attr_name.clone(), cid_left.clone());
902 #[allow(clippy::todo)]
903 if let Some(merged_attr_state) =
904 vs_left.repl_merge_valueset(vs_right, trim_cid)
905 {
906 eattrs.insert(attr_name.clone(), merged_attr_state);
909 } else {
910 eattrs.insert(attr_name.clone(), vs_left.clone());
911 }
912 }
913 (Some(vs_left), Some(vs_right)) => {
914 changes.insert(attr_name.clone(), cid_right.clone());
915 #[allow(clippy::todo)]
916 if let Some(merged_attr_state) =
917 vs_right.repl_merge_valueset(vs_left, trim_cid)
918 {
919 eattrs.insert(attr_name.clone(), merged_attr_state);
922 } else {
923 eattrs.insert(attr_name.clone(), vs_right.clone());
924 }
925 }
926 (Some(vs_left), None) if take_left => {
927 changes.insert(attr_name.clone(), cid_left.clone());
928 eattrs.insert(attr_name.clone(), vs_left.clone());
929 }
930 (Some(_vs_left), None) => {
931 changes.insert(attr_name.clone(), cid_right.clone());
932 }
934 (None, Some(_vs_right)) if take_left => {
935 changes.insert(attr_name.clone(), cid_left.clone());
936 }
938 (None, Some(vs_right)) => {
939 changes.insert(attr_name.clone(), cid_right.clone());
940 eattrs.insert(attr_name.clone(), vs_right.clone());
941 }
942 (None, None) if take_left => {
943 changes.insert(attr_name.clone(), cid_left.clone());
944 }
946 (None, None) => {
947 changes.insert(attr_name.clone(), cid_right.clone());
948 }
950 }
951 }
953 (Some(cid_left), None) => {
954 changes.insert(attr_name.clone(), cid_left.clone());
956 if let Some(valueset) = self.attrs.get(attr_name) {
957 eattrs.insert(attr_name.clone(), valueset.clone());
958 }
959 }
960 (None, Some(cid_right)) => {
961 changes.insert(attr_name.clone(), cid_right.clone());
963 if let Some(valueset) = db_ent.attrs.get(attr_name) {
964 eattrs.insert(attr_name.clone(), valueset.clone());
965 }
966 }
967 (None, None) => {
968 debug_assert!(false);
970 }
971 }
972 }
973
974 let mut ecstate = EntryChangeState::build(State::Live {
975 at: at_left.clone(),
976 changes,
977 });
978
979 ecstate.retain(|k, _| schema.is_replicated(k));
983
984 let cv = vs_cid![ecstate.get_max_cid().clone()];
985 let _ = eattrs.insert(Attribute::LastModifiedCid, cv);
986
987 let cv = vs_cid![ecstate.at().clone()];
988 let _ = eattrs.insert(Attribute::CreatedAtCid, cv);
989
990 Entry {
991 valid: EntryIncremental {
992 uuid: self.valid.uuid,
993 ecstate,
994 },
995 state: EntryCommitted {
996 id: db_ent.state.id,
997 },
998 attrs: eattrs,
999 }
1000 }
1001 (State::Tombstone { at: left_at }, State::Live { .. }) => {
1002 let mut attrs_new: Eattrs = Map::new();
1006 let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()];
1007 let last_mod_ava = vs_cid![left_at.clone()];
1008 let created_ava = vs_cid![left_at.clone()];
1009
1010 attrs_new.insert(Attribute::Uuid, vs_uuid![self.valid.uuid]);
1011 attrs_new.insert(Attribute::Class, class_ava);
1012 attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava);
1013 attrs_new.insert(Attribute::CreatedAtCid, created_ava);
1014
1015 Entry {
1016 valid: EntryIncremental {
1017 uuid: self.valid.uuid,
1018 ecstate: self.valid.ecstate.clone(),
1019 },
1020 state: EntryCommitted {
1021 id: db_ent.state.id,
1022 },
1023 attrs: attrs_new,
1024 }
1025 }
1026 (State::Live { .. }, State::Tombstone { .. }) => {
1027 Entry {
1035 valid: EntryIncremental {
1036 uuid: db_ent.valid.uuid,
1037 ecstate: db_ent.valid.ecstate.clone(),
1038 },
1039 state: EntryCommitted {
1040 id: db_ent.state.id,
1041 },
1042 attrs: db_ent.attrs.clone(),
1043 }
1044 }
1045 (State::Tombstone { at: left_at }, State::Tombstone { at: right_at }) => {
1046 let (at, ecstate) = if left_at < right_at {
1051 (left_at, self.valid.ecstate.clone())
1052 } else {
1053 (right_at, db_ent.valid.ecstate.clone())
1054 };
1055
1056 let mut attrs_new: Eattrs = Map::new();
1057 let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()];
1058 let last_mod_ava = vs_cid![at.clone()];
1059 let created_ava = vs_cid![at.clone()];
1060
1061 attrs_new.insert(Attribute::Uuid, vs_uuid![db_ent.valid.uuid]);
1062 attrs_new.insert(Attribute::Class, class_ava);
1063 attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava);
1064 attrs_new.insert(Attribute::CreatedAtCid, created_ava);
1065
1066 Entry {
1067 valid: EntryIncremental {
1068 uuid: db_ent.valid.uuid,
1069 ecstate,
1070 },
1071 state: EntryCommitted {
1072 id: db_ent.state.id,
1073 },
1074 attrs: attrs_new,
1075 }
1076 }
1077 }
1078 }
1079}
1080
1081impl Entry<EntryIncremental, EntryCommitted> {
1082 pub(crate) fn validate_repl(self, schema: &dyn SchemaTransaction) -> EntryValidCommitted {
1083 let mut ne = Entry {
1088 valid: EntryValid {
1089 uuid: self.valid.uuid,
1090 ecstate: self.valid.ecstate,
1091 },
1092 state: self.state,
1093 attrs: self.attrs,
1094 };
1095
1096 if let Err(e) = ne.validate(schema) {
1097 warn!(uuid = ?self.valid.uuid, err = ?e, "Entry failed schema check, moving to a conflict state");
1098 ne.add_ava_int(Attribute::Class, EntryClass::Recycled.into());
1099 ne.add_ava_int(Attribute::Class, EntryClass::Conflict.into());
1100 ne.add_ava_int(Attribute::SourceUuid, Value::Uuid(self.valid.uuid));
1101 }
1102 ne
1103 }
1104}
1105
1106impl<STATE> Entry<EntryInvalid, STATE> {
1107 pub(crate) fn get_uuid(&self) -> Option<Uuid> {
1108 self.attrs
1109 .get(&Attribute::Uuid)
1110 .and_then(|vs| vs.to_uuid_single())
1111 }
1112
1113 pub fn validate(
1116 self,
1117 schema: &dyn SchemaTransaction,
1118 ) -> Result<Entry<EntryValid, STATE>, SchemaError> {
1119 let uuid: Uuid = self
1120 .attrs
1121 .get(&Attribute::Uuid)
1122 .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
1123 .and_then(|vs| {
1124 vs.to_uuid_single()
1125 .ok_or_else(|| SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
1126 })?;
1127
1128 let ne = Entry {
1130 valid: EntryValid {
1131 uuid,
1132 ecstate: self.valid.ecstate,
1133 },
1134 state: self.state,
1135 attrs: self.attrs,
1136 };
1137
1138 ne.validate(schema).map(|()| ne)
1139 }
1140
1141 pub(crate) fn get_ava_refer_mut<A: AsRef<Attribute>>(
1145 &mut self,
1146 attr: A,
1147 ) -> Option<&mut BTreeSet<Uuid>> {
1148 self.get_ava_mut(attr).and_then(|vs| vs.as_refer_set_mut())
1149 }
1150
1151 pub(crate) fn get_ava_mut<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<&mut ValueSet> {
1152 let attr_ref = attr.as_ref();
1153 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
1154 self.attrs.get_mut(attr.as_ref())
1155 }
1156}
1157
1158impl<VALID, STATE> Clone for Entry<VALID, STATE>
1159where
1160 VALID: Clone,
1161 STATE: Clone,
1162{
1163 fn clone(&self) -> Entry<VALID, STATE> {
1165 Entry {
1166 valid: self.valid.clone(),
1167 state: self.state.clone(),
1168 attrs: self.attrs.clone(),
1169 }
1170 }
1171}
1172
1173impl Entry<EntryInvalid, EntryCommitted> {
1174 #[cfg(test)]
1178 pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
1179 let uuid = self.get_uuid().expect("Invalid uuid");
1180 Entry {
1181 valid: EntryValid {
1182 uuid,
1183 ecstate: self.valid.ecstate,
1184 },
1185 state: EntryNew,
1186 attrs: self.attrs,
1187 }
1188 }
1189
1190 pub fn to_recycled(mut self) -> Self {
1192 self.add_ava(Attribute::Class, EntryClass::Recycled.into());
1194
1195 Entry {
1199 valid: self.valid,
1200 state: self.state,
1201 attrs: self.attrs,
1202 }
1203 }
1204
1205 pub fn to_conflict<T>(&mut self, iter: T)
1207 where
1208 T: IntoIterator<Item = Uuid>,
1209 {
1210 self.add_ava(Attribute::Class, EntryClass::Recycled.into());
1211 self.add_ava(Attribute::Class, EntryClass::Conflict.into());
1212 for source_uuid in iter {
1214 self.add_ava(Attribute::SourceUuid, Value::Uuid(source_uuid));
1215 }
1216 }
1217
1218 pub fn to_revived(mut self) -> Self {
1220 self.remove_ava(Attribute::Class, &EntryClass::Recycled.into());
1222 self.remove_ava(Attribute::Class, &EntryClass::Conflict.into());
1223
1224 self.purge_ava(Attribute::CascadeDeleted);
1225 self.purge_ava(Attribute::SourceUuid);
1226 self.purge_ava(Attribute::RecycledDirectMemberOf);
1227
1228 Entry {
1232 valid: self.valid,
1233 state: self.state,
1234 attrs: self.attrs,
1235 }
1236 }
1237}
1238impl Entry<EntryInvalid, EntryNew> {
1241 #[cfg(test)]
1244 pub fn into_init_new(self) -> Entry<EntryInit, EntryNew> {
1245 Entry {
1246 valid: EntryInit,
1247 state: EntryNew,
1248 attrs: self.attrs,
1249 }
1250 }
1251
1252 #[cfg(test)]
1256 pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
1257 let uuid = self.get_uuid().expect("Invalid uuid");
1258 Entry {
1259 valid: EntryValid {
1260 uuid,
1261 ecstate: self.valid.ecstate,
1262 },
1263 state: EntryNew,
1264 attrs: self.attrs,
1265 }
1266 }
1267
1268 #[cfg(test)]
1272 pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1273 let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
1274 Entry {
1275 valid: EntrySealed {
1276 uuid,
1277 ecstate: self.valid.ecstate,
1278 },
1279 state: EntryCommitted { id: 0 },
1280 attrs: self.attrs,
1281 }
1282 }
1283
1284 #[cfg(test)]
1288 pub fn into_valid_committed(self) -> Entry<EntryValid, EntryCommitted> {
1289 let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
1290 Entry {
1291 valid: EntryValid {
1292 uuid,
1293 ecstate: self.valid.ecstate,
1294 },
1295 state: EntryCommitted { id: 0 },
1296 attrs: self.attrs,
1297 }
1298 }
1299}
1300
1301impl Entry<EntryInvalid, EntryCommitted> {
1302 #[cfg(test)]
1306 pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1307 let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
1308 Entry {
1309 valid: EntrySealed {
1310 uuid,
1311 ecstate: self.valid.ecstate,
1312 },
1313 state: self.state,
1314 attrs: self.attrs,
1315 }
1316 }
1317}
1318
1319impl Entry<EntrySealed, EntryNew> {
1320 #[cfg(test)]
1324 pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1325 Entry {
1326 valid: self.valid,
1327 state: EntryCommitted { id: 0 },
1328 attrs: self.attrs,
1329 }
1330 }
1331
1332 pub fn into_sealed_committed_id(self, id: u64) -> Entry<EntrySealed, EntryCommitted> {
1335 Entry {
1336 valid: self.valid,
1337 state: EntryCommitted { id },
1338 attrs: self.attrs,
1339 }
1340 }
1341
1342 pub fn compare(&self, rhs: &Entry<EntrySealed, EntryNew>) -> bool {
1343 compare_attrs(&self.attrs, &rhs.attrs)
1344 }
1345}
1346
1347type IdxDiff<'a> =
1348 Vec<Result<(&'a Attribute, IndexType, String), (&'a Attribute, IndexType, String)>>;
1349
1350impl<VALID> Entry<VALID, EntryCommitted> {
1351 pub fn get_id(&self) -> u64 {
1353 self.state.id
1354 }
1355}
1356
1357impl<STATE> Entry<EntrySealed, STATE> {
1358 pub fn into_init(self) -> Entry<EntryInit, STATE> {
1359 Entry {
1360 valid: EntryInit,
1361 state: self.state,
1362 attrs: self.attrs,
1363 }
1364 }
1365}
1366
1367impl Entry<EntrySealed, EntryCommitted> {
1368 #[cfg(test)]
1369 pub(crate) fn get_last_changed(&self) -> Cid {
1370 self.valid.ecstate.get_max_cid().clone()
1371 }
1372
1373 #[cfg(test)]
1375 pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
1376 self
1378 }
1379
1380 pub(crate) fn stub_sealed_committed_id(
1381 id: u64,
1382 ctx_ent: &EntryIncrementalNew,
1383 ) -> EntrySealedCommitted {
1384 let uuid = ctx_ent.get_uuid();
1385 let ecstate = ctx_ent.stub_ecstate();
1386
1387 Entry {
1388 valid: EntrySealed { uuid, ecstate },
1389 state: EntryCommitted { id },
1390 attrs: Default::default(),
1391 }
1392 }
1393
1394 pub fn insert_claim(&mut self, value: &str) {
1397 self.add_ava_int(Attribute::Claim, Value::new_iutf8(value));
1398 }
1399
1400 pub fn compare(&self, rhs: &Entry<EntrySealed, EntryCommitted>) -> bool {
1401 compare_attrs(&self.attrs, &rhs.attrs)
1402 }
1403
1404 pub fn to_dbentry(&self) -> DbEntry {
1406 DbEntry {
1409 ent: DbEntryVers::V3 {
1410 changestate: self.valid.ecstate.to_db_changestate(),
1411 attrs: self
1412 .attrs
1413 .iter()
1414 .map(|(k, vs)| {
1415 let dbvs: DbValueSetV2 = vs.to_db_valueset_v2();
1416 (k.clone(), dbvs)
1417 })
1418 .collect(),
1419 },
1420 }
1421 }
1422
1423 #[inline]
1424 fn get_name2uuid_cands(&self) -> Set<String> {
1427 let cands = [Attribute::Spn, Attribute::Name, Attribute::GidNumber];
1433 cands
1434 .iter()
1435 .filter_map(|cand| {
1436 self.attrs
1437 .get(cand)
1438 .map(|vs| vs.to_proto_string_clone_iter())
1439 })
1440 .flatten()
1441 .collect()
1442 }
1443
1444 #[inline]
1445 fn get_externalid2uuid(&self) -> Option<String> {
1448 self.attrs
1449 .get(&Attribute::SyncExternalId)
1450 .and_then(|vs| vs.to_proto_string_single())
1451 }
1452
1453 #[inline]
1454 pub(crate) fn get_uuid2spn(&self) -> Value {
1457 self.attrs
1458 .get(&Attribute::Spn)
1459 .and_then(|vs| vs.to_value_single())
1460 .or_else(|| {
1461 self.attrs
1462 .get(&Attribute::Name)
1463 .and_then(|vs| vs.to_value_single())
1464 })
1465 .unwrap_or_else(|| Value::Uuid(self.get_uuid()))
1466 }
1467
1468 #[inline]
1469 pub(crate) fn get_uuid2rdn(&self) -> String {
1473 self.attrs
1474 .get(&Attribute::Spn)
1475 .and_then(|vs| vs.to_proto_string_single().map(|v| format!("spn={v}")))
1476 .or_else(|| {
1477 self.attrs
1478 .get(&Attribute::Name)
1479 .and_then(|vs| vs.to_proto_string_single().map(|v| format!("name={v}")))
1480 })
1481 .unwrap_or_else(|| format!("uuid={}", self.get_uuid().as_hyphenated()))
1482 }
1483
1484 pub(crate) fn idx_name2uuid_diff(
1487 pre: Option<&Self>,
1488 post: Option<&Self>,
1489 ) -> (
1490 Option<Set<String>>,
1492 Option<Set<String>>,
1494 ) {
1495 match (pre, post) {
1497 (None, None) => {
1498 (None, None)
1500 }
1501 (None, Some(b)) => {
1502 (Some(b.get_name2uuid_cands()), None)
1505 }
1506 (Some(a), None) => {
1507 (None, Some(a.get_name2uuid_cands()))
1509 }
1510 (Some(a), Some(b)) => {
1511 let pre_set = a.get_name2uuid_cands();
1512 let post_set = b.get_name2uuid_cands();
1513
1514 let add_set: Set<_> = post_set.difference(&pre_set).cloned().collect();
1516 let rem_set: Set<_> = pre_set.difference(&post_set).cloned().collect();
1518 (Some(add_set), Some(rem_set))
1519 }
1520 }
1521 }
1522
1523 pub(crate) fn idx_externalid2uuid_diff(
1525 pre: Option<&Self>,
1526 post: Option<&Self>,
1527 ) -> (Option<String>, Option<String>) {
1528 match (pre, post) {
1529 (None, None) => {
1530 (None, None)
1532 }
1533 (None, Some(b)) => {
1534 (b.get_externalid2uuid(), None)
1536 }
1537 (Some(a), None) => {
1538 (None, a.get_externalid2uuid())
1540 }
1541 (Some(a), Some(b)) => {
1542 let ia = a.get_externalid2uuid();
1543 let ib = b.get_externalid2uuid();
1544 if ia != ib {
1545 (ib, ia)
1548 } else {
1549 (None, None)
1551 }
1552 }
1553 }
1554 }
1555
1556 pub(crate) fn idx_uuid2spn_diff(
1559 pre: Option<&Self>,
1560 post: Option<&Self>,
1561 ) -> Option<Result<Value, ()>> {
1562 match (pre, post) {
1563 (None, None) => {
1564 None
1566 }
1567 (None, Some(b)) => {
1568 Some(Ok(b.get_uuid2spn()))
1570 }
1571 (Some(_a), None) => {
1572 Some(Err(()))
1574 }
1575 (Some(a), Some(b)) => {
1576 let ia = a.get_uuid2spn();
1577 let ib = b.get_uuid2spn();
1578 if ia != ib {
1579 Some(Ok(ib))
1581 } else {
1582 None
1584 }
1585 }
1586 }
1587 }
1588
1589 pub(crate) fn idx_uuid2rdn_diff(
1592 pre: Option<&Self>,
1593 post: Option<&Self>,
1594 ) -> Option<Result<String, ()>> {
1595 match (pre, post) {
1596 (None, None) => {
1597 None
1599 }
1600 (None, Some(b)) => {
1601 Some(Ok(b.get_uuid2rdn()))
1603 }
1604 (Some(_a), None) => {
1605 Some(Err(()))
1607 }
1608 (Some(a), Some(b)) => {
1609 let ia = a.get_uuid2rdn();
1610 let ib = b.get_uuid2rdn();
1611 if ia != ib {
1612 Some(Ok(ib))
1614 } else {
1615 None
1617 }
1618 }
1619 }
1620 }
1621
1622 pub(crate) fn idx_diff<'a>(
1625 idxmeta: &'a HashMap<IdxKey, IdxSlope>,
1626 pre: Option<&Self>,
1627 post: Option<&Self>,
1628 ) -> IdxDiff<'a> {
1629 match (pre, post) {
1634 (None, None) => {
1635 Vec::with_capacity(0)
1637 }
1638 (Some(pre_e), None) => {
1639 idxmeta
1641 .keys()
1642 .flat_map(|ikey| {
1643 match pre_e.get_ava_set(&ikey.attr) {
1644 None => Vec::with_capacity(0),
1645 Some(vs) => {
1646 let changes: Vec<Result<_, _>> = match ikey.itype {
1647 IndexType::Equality => {
1648 vs.generate_idx_eq_keys()
1650 .into_iter()
1651 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1652 .collect()
1653 }
1654 IndexType::Presence => {
1655 vec![Err((&ikey.attr, ikey.itype, "_".to_string()))]
1656 }
1657 IndexType::SubString => vs
1658 .generate_idx_sub_keys()
1659 .into_iter()
1660 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1661 .collect(),
1662 IndexType::Ordering => vs
1663 .generate_idx_ord_keys()
1664 .into_iter()
1665 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1666 .collect(),
1667 };
1668 changes
1669 }
1670 }
1671 })
1672 .collect()
1673 }
1674 (None, Some(post_e)) => {
1675 idxmeta
1677 .keys()
1678 .flat_map(|ikey| {
1679 match post_e.get_ava_set(&ikey.attr) {
1680 None => Vec::with_capacity(0),
1681 Some(vs) => {
1682 let changes: Vec<Result<_, _>> = match ikey.itype {
1683 IndexType::Equality => vs
1684 .generate_idx_eq_keys()
1685 .into_iter()
1686 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1687 .collect(),
1688 IndexType::Presence => {
1689 vec![Ok((&ikey.attr, ikey.itype, "_".to_string()))]
1690 }
1691 IndexType::SubString => vs
1692 .generate_idx_sub_keys()
1693 .into_iter()
1694 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1695 .collect(),
1696 IndexType::Ordering => vs
1697 .generate_idx_ord_keys()
1698 .into_iter()
1699 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1700 .collect(),
1701 };
1702 changes
1705 }
1706 }
1707 })
1708 .collect()
1709 }
1710 (Some(pre_e), Some(post_e)) => {
1711 assert_eq!(pre_e.state.id, post_e.state.id);
1712 idxmeta
1713 .keys()
1714 .flat_map(|ikey| {
1715 match (
1716 pre_e.get_ava_set(&ikey.attr),
1717 post_e.get_ava_set(&ikey.attr),
1718 ) {
1719 (None, None) => {
1720 Vec::with_capacity(0)
1722 }
1723 (Some(pre_vs), None) => {
1724 let changes: Vec<Result<_, _>> = match ikey.itype {
1726 IndexType::Equality => {
1727 pre_vs
1730 .generate_idx_eq_keys()
1731 .into_iter()
1732 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1733 .collect()
1734 }
1735 IndexType::Presence => {
1736 vec![Err((&ikey.attr, ikey.itype, "_".to_string()))]
1737 }
1738 IndexType::SubString => pre_vs
1739 .generate_idx_sub_keys()
1740 .into_iter()
1741 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1742 .collect(),
1743 IndexType::Ordering => pre_vs
1744 .generate_idx_ord_keys()
1745 .into_iter()
1746 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1747 .collect(),
1748 };
1749 changes
1750 }
1751 (None, Some(post_vs)) => {
1752 let changes: Vec<Result<_, _>> = match ikey.itype {
1754 IndexType::Equality => {
1755 post_vs
1758 .generate_idx_eq_keys()
1759 .into_iter()
1760 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1761 .collect()
1762 }
1763 IndexType::Presence => {
1764 vec![Ok((&ikey.attr, ikey.itype, "_".to_string()))]
1765 }
1766 IndexType::SubString => post_vs
1767 .generate_idx_sub_keys()
1768 .into_iter()
1769 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1770 .collect(),
1771 IndexType::Ordering => post_vs
1772 .generate_idx_ord_keys()
1773 .into_iter()
1774 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1775 .collect(),
1776 };
1777 changes
1778 }
1779 (Some(pre_vs), Some(post_vs)) => {
1780 let (mut pre_idx_keys, mut post_idx_keys) = match ikey.itype {
1782 IndexType::Equality => (
1783 pre_vs.generate_idx_eq_keys(),
1784 post_vs.generate_idx_eq_keys(),
1785 ),
1786 IndexType::Presence => {
1787 (Vec::with_capacity(0), Vec::with_capacity(0))
1789 }
1790 IndexType::SubString => (
1791 pre_vs.generate_idx_sub_keys(),
1792 post_vs.generate_idx_sub_keys(),
1793 ),
1794 IndexType::Ordering => (
1795 pre_vs.generate_idx_ord_keys(),
1796 post_vs.generate_idx_ord_keys(),
1797 ),
1798 };
1799
1800 let sz = if pre_idx_keys.len() > post_idx_keys.len() {
1801 pre_idx_keys.len()
1802 } else {
1803 post_idx_keys.len()
1804 };
1805
1806 let mut added_vs = Vec::with_capacity(sz);
1807 let mut removed_vs = Vec::with_capacity(sz);
1808
1809 if sz > 0 {
1810 pre_idx_keys.sort_unstable();
1811 post_idx_keys.sort_unstable();
1812
1813 let mut pre_iter = pre_idx_keys.iter();
1814 let mut post_iter = post_idx_keys.iter();
1815
1816 let mut pre = pre_iter.next();
1817 let mut post = post_iter.next();
1818
1819 loop {
1820 match (pre, post) {
1821 (Some(a), Some(b)) => {
1822 match a.cmp(b) {
1823 Ordering::Less => {
1824 removed_vs.push(a.clone());
1825 pre = pre_iter.next();
1826 }
1827 Ordering::Equal => {
1828 pre = pre_iter.next();
1830 post = post_iter.next();
1831 }
1832 Ordering::Greater => {
1833 added_vs.push(b.clone());
1834 post = post_iter.next();
1835 }
1836 }
1837 }
1838 (Some(a), None) => {
1839 removed_vs.push(a.clone());
1840 pre = pre_iter.next();
1841 }
1842 (None, Some(b)) => {
1843 added_vs.push(b.clone());
1844 post = post_iter.next();
1845 }
1846 (None, None) => {
1847 break;
1848 }
1849 }
1850 }
1851 } let mut diff =
1854 Vec::with_capacity(removed_vs.len() + added_vs.len());
1855
1856 match ikey.itype {
1857 IndexType::SubString
1858 | IndexType::Ordering
1859 | IndexType::Equality => {
1860 removed_vs
1861 .into_iter()
1862 .map(|idx_key| Err((&ikey.attr, ikey.itype, idx_key)))
1863 .for_each(|v| diff.push(v));
1864 added_vs
1865 .into_iter()
1866 .map(|idx_key| Ok((&ikey.attr, ikey.itype, idx_key)))
1867 .for_each(|v| diff.push(v));
1868 }
1869 IndexType::Presence => {
1870 }
1872 };
1873 diff
1875 }
1876 }
1877 })
1878 .collect()
1879 }
1881 }
1882 }
1883
1884 pub fn from_dbentry(db_e: DbEntry, id: u64) -> Option<Self> {
1885 let (attrs, ecstate) = match db_e.ent {
1888 DbEntryVers::V3 { changestate, attrs } => {
1889 let ecstate = EntryChangeState::from_db_changestate(changestate);
1890
1891 let r_attrs = attrs
1892 .into_iter()
1893 .filter(|(_k, vs)| !vs.is_empty())
1895 .map(|(k, dbvs)| {
1896 valueset::from_db_valueset_v2(dbvs)
1897 .map(|vs: ValueSet| (k, vs))
1898 .map_err(|e| {
1899 error!(?e, "from_dbentry failed");
1900 })
1901 })
1902 .collect::<Result<Eattrs, ()>>()
1903 .ok()?;
1904
1905 (r_attrs, ecstate)
1906 }
1907 };
1908
1909 let uuid = attrs
1910 .get(&Attribute::Uuid)
1911 .and_then(|vs| vs.to_uuid_single())?;
1912
1913 Some(Entry {
1914 valid: EntrySealed { uuid, ecstate },
1915 state: EntryCommitted { id },
1916 attrs,
1917 })
1918 }
1919
1920 #[cfg(test)]
1928 pub(crate) fn into_reduced(self) -> Entry<EntryReduced, EntryCommitted> {
1929 Entry {
1930 valid: EntryReduced {
1931 uuid: self.valid.uuid,
1932 effective_access: None,
1933 },
1934 state: self.state,
1935 attrs: self.attrs,
1936 }
1937 }
1938
1939 pub fn reduce_attributes(
1942 &self,
1943 allowed_attrs: &BTreeSet<Attribute>,
1944 effective_access: Option<Box<AccessEffectivePermission>>,
1945 ) -> Entry<EntryReduced, EntryCommitted> {
1946 let f_attrs: Map<_, _> = self
1948 .attrs
1949 .iter()
1950 .filter_map(|(k, v)| {
1951 if allowed_attrs.contains(k) {
1952 Some((k.clone(), v.clone()))
1953 } else {
1954 None
1955 }
1956 })
1957 .collect();
1958
1959 let valid = EntryReduced {
1960 uuid: self.valid.uuid,
1961 effective_access,
1962 };
1963 let state = self.state.clone();
1964
1965 Entry {
1966 valid,
1967 state,
1968 attrs: f_attrs,
1969 }
1970 }
1971
1972 pub fn to_tombstone(&self, cid: Cid) -> Entry<EntryInvalid, EntryCommitted> {
1974 let mut ecstate = self.valid.ecstate.clone();
1975 let mut attrs_new: Eattrs = Map::new();
1977
1978 let class_ava = vs_iutf8![EntryClass::Object.into(), EntryClass::Tombstone.into()];
1979 let last_mod_ava = vs_cid![cid.clone()];
1980 let created_ava = vs_cid![cid.clone()];
1981
1982 attrs_new.insert(Attribute::Uuid, vs_uuid![self.get_uuid()]);
1983 attrs_new.insert(Attribute::Class, class_ava);
1984 attrs_new.insert(Attribute::LastModifiedCid, last_mod_ava);
1985 attrs_new.insert(Attribute::CreatedAtCid, created_ava);
1986
1987 ecstate.tombstone(&cid);
1989
1990 Entry {
1991 valid: EntryInvalid { cid, ecstate },
1992 state: self.state.clone(),
1993 attrs: attrs_new,
1994 }
1995 }
1996
1997 pub fn into_valid(self, ecstate: EntryChangeState) -> Entry<EntryValid, EntryCommitted> {
1999 Entry {
2000 valid: EntryValid {
2001 uuid: self.valid.uuid,
2002 ecstate,
2003 },
2004 state: self.state,
2005 attrs: self.attrs,
2006 }
2007 }
2008
2009 pub fn verify(
2010 &self,
2011 schema: &dyn SchemaTransaction,
2012 results: &mut Vec<Result<(), ConsistencyError>>,
2013 ) {
2014 self.valid
2015 .ecstate
2016 .verify(schema, &self.attrs, self.state.id, results);
2017 }
2018}
2019
2020impl<STATE> Entry<EntryValid, STATE> {
2021 fn validate(&self, schema: &dyn SchemaTransaction) -> Result<(), SchemaError> {
2022 let schema_classes = schema.get_classes();
2023 let schema_attributes = schema.get_attributes();
2024
2025 trace!(?self.attrs, "Entry::validate -> target");
2027
2028 if !self.attribute_pres(Attribute::Class) {
2030 return Err(SchemaError::NoClassFound);
2032 }
2033
2034 if self.attribute_equality(Attribute::Class, &EntryClass::Conflict.into()) {
2035 trace!("Skipping schema validation on conflict entry");
2037 return Ok(());
2038 };
2039
2040 let recycled = self.attribute_equality(Attribute::Class, &EntryClass::Recycled.into());
2042
2043 let extensible =
2046 self.attribute_equality(Attribute::Class, &EntryClass::ExtensibleObject.into());
2047
2048 let entry_classes = self.get_ava_set(Attribute::Class).ok_or_else(|| {
2049 admin_debug!("Attribute '{}' missing from entry", Attribute::Class);
2050 SchemaError::NoClassFound
2051 })?;
2052 let mut invalid_classes = Vec::with_capacity(0);
2053
2054 let mut classes: Vec<&SchemaClass> = Vec::with_capacity(entry_classes.len());
2055
2056 let entry_classes = if let Some(ec) = entry_classes.as_iutf8_set() {
2059 ec.iter()
2060 .for_each(|s| match schema_classes.get(s.as_str()) {
2061 Some(x) => classes.push(x),
2062 None => {
2063 admin_debug!("invalid class: {:?}", s);
2064 invalid_classes.push(s.to_string())
2065 }
2066 });
2067 ec
2068 } else {
2069 admin_debug!("corrupt class attribute");
2070 return Err(SchemaError::NoClassFound);
2071 };
2072
2073 if !invalid_classes.is_empty() {
2074 return Err(SchemaError::InvalidClass(invalid_classes));
2075 };
2076
2077 let supplements_classes: Vec<_> = classes
2081 .iter()
2082 .flat_map(|cls| cls.systemsupplements.iter().chain(cls.supplements.iter()))
2083 .collect();
2084
2085 let valid_supplements = if supplements_classes.is_empty() {
2087 true
2089 } else {
2090 supplements_classes
2091 .iter()
2092 .any(|class| entry_classes.contains(class.as_str()))
2093 };
2094
2095 if !valid_supplements {
2096 warn!(
2097 "Validation error, the following possible supplement classes are missing - {:?}",
2098 supplements_classes
2099 );
2100 let supplements_classes = supplements_classes.iter().map(|s| s.to_string()).collect();
2101 return Err(SchemaError::SupplementsNotSatisfied(supplements_classes));
2102 }
2103
2104 let excludes_classes: Vec<_> = classes
2105 .iter()
2106 .flat_map(|cls| cls.systemexcludes.iter().chain(cls.excludes.iter()))
2107 .collect();
2108
2109 let mut invalid_excludes = Vec::with_capacity(0);
2110
2111 excludes_classes.iter().for_each(|class| {
2112 if entry_classes.contains(class.as_str()) {
2113 invalid_excludes.push(class.to_string())
2114 }
2115 });
2116
2117 if !invalid_excludes.is_empty() {
2118 admin_warn!(
2119 "Validation error, the following excluded classes are present - {:?}",
2120 invalid_excludes
2121 );
2122 return Err(SchemaError::ExcludesNotSatisfied(invalid_excludes));
2123 }
2124
2125 let must: Result<Vec<&SchemaAttribute>, _> = classes
2138 .iter()
2139 .flat_map(|cls| cls.systemmust.iter().chain(cls.must.iter()))
2141 .map(|s| {
2142 schema_attributes.get(s).ok_or(SchemaError::Corrupted)
2145 })
2146 .collect();
2147
2148 let must = must?;
2149
2150 let mut missing_must = Vec::with_capacity(0);
2153 for attr in must.iter() {
2154 let avas = self.get_ava_set(&attr.name);
2155 if avas.is_none() {
2156 missing_must.push(attr.name.clone());
2157 }
2158 }
2159
2160 if !missing_must.is_empty() {
2161 admin_warn!(
2162 "Validation error, the following required ({}) (must) attributes are missing - {:?}",
2163 self.get_display_id(), missing_must
2164 );
2165 if !recycled {
2171 return Err(SchemaError::MissingMustAttribute(missing_must));
2172 }
2173 }
2174
2175 if extensible {
2176 self.attrs.iter().try_for_each(|(attr_name, avas)| {
2177 match schema_attributes.get(attr_name) {
2178 Some(a_schema) => {
2179 if a_schema.phantom {
2182 admin_warn!(
2183 "Rejecting attempt to add phantom attribute to extensible object: {}",
2184 attr_name
2185 );
2186 Err(SchemaError::PhantomAttribute(attr_name.to_string()))
2187 } else {
2188 a_schema.validate_ava(attr_name, avas)
2189 }
2191 }
2192 None => {
2193 admin_error!(
2194 "Invalid Attribute {}, undefined in schema_attributes",
2195 attr_name.to_string()
2196 );
2197 Err(SchemaError::InvalidAttribute(
2198 attr_name.to_string()
2199 ))
2200 }
2201 }
2202 })?;
2203 } else {
2204 let may: Result<Map<&Attribute, &SchemaAttribute>, _> = classes
2212 .iter()
2213 .flat_map(|cls| {
2215 trace!(?cls);
2216 cls.systemmust
2217 .iter()
2218 .chain(cls.must.iter())
2219 .chain(cls.systemmay.iter())
2220 .chain(cls.may.iter())
2221 })
2222 .map(|s| {
2223 Ok((s, schema_attributes.get(s).ok_or(SchemaError::Corrupted)?))
2226 })
2227 .collect();
2228
2229 let may = may?;
2230
2231 self.attrs.iter().try_for_each(|(attr_name, avas)| {
2240 match may.get(attr_name) {
2241 Some(a_schema) => {
2242 a_schema.validate_ava(attr_name, avas)
2245 }
2247 None => {
2248 admin_error!(
2249 "{} {} - not found in the list of valid attributes for this set of classes {:?} - valid attributes are {:?}",
2250
2251 attr_name.as_str(),
2252 self.get_display_id(),
2253 entry_classes.iter().collect::<Vec<_>>(),
2254 may.keys().collect::<Vec<_>>()
2255 );
2256 Err(SchemaError::AttributeNotValidForClass(
2257 attr_name.to_string()
2258 ))
2259 }
2260 }
2261 })?;
2262 }
2263
2264 Ok(())
2266 }
2267
2268 pub fn seal(mut self, schema: &dyn SchemaTransaction) -> Entry<EntrySealed, STATE> {
2269 let EntryValid { uuid, mut ecstate } = self.valid;
2270
2271 ecstate.retain(|k, _| schema.is_replicated(k));
2275
2276 let last_mod_cid = ecstate.get_max_cid();
2278 let cv = vs_cid![last_mod_cid.clone()];
2279 let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
2280
2281 let create_at_cid = ecstate.at();
2285 let cv = vs_cid![create_at_cid.clone()];
2286 let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
2287
2288 Entry {
2289 valid: EntrySealed { uuid, ecstate },
2290 state: self.state,
2291 attrs: self.attrs,
2292 }
2293 }
2294
2295 pub fn get_uuid(&self) -> Uuid {
2296 self.valid.uuid
2297 }
2298}
2299
2300impl<STATE> GetUuid for Entry<EntrySealed, STATE>
2301where
2302 STATE: Clone,
2303{
2304 fn get_uuid(&self) -> Uuid {
2305 self.valid.uuid
2306 }
2307}
2308
2309impl<STATE> Entry<EntrySealed, STATE>
2310where
2311 STATE: Clone,
2312{
2313 pub fn invalidate(mut self, cid: Cid, trim_cid: &Cid) -> Entry<EntryInvalid, STATE> {
2314 for vs in self.attrs.values_mut() {
2316 vs.trim(trim_cid);
2317 }
2318
2319 let last_mod_cid = self.valid.ecstate.get_max_cid();
2327 let cv = vs_cid![last_mod_cid.clone()];
2328 let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
2329
2330 let create_at_cid = self.valid.ecstate.at();
2331 let cv = vs_cid![create_at_cid.clone()];
2332 let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
2333
2334 Entry {
2335 valid: EntryInvalid {
2336 cid,
2337 ecstate: self.valid.ecstate,
2338 },
2339 state: self.state,
2340 attrs: self.attrs,
2341 }
2342 }
2343
2344 pub fn get_uuid(&self) -> Uuid {
2345 self.valid.uuid
2346 }
2347
2348 pub fn get_changestate(&self) -> &EntryChangeState {
2349 &self.valid.ecstate
2350 }
2351
2352 pub(crate) fn entry_changed_excluding_attribute<A: AsRef<Attribute>>(
2356 &self,
2357 attr: A,
2358 cid: &Cid,
2359 ) -> bool {
2360 let attr_ref = attr.as_ref();
2361
2362 use crate::repl::entry::State;
2363
2364 match self.get_changestate().current() {
2365 State::Live { at: _, changes } => {
2366 changes.iter().any(|(change_attr, change_id)| {
2367 change_id >= cid &&
2368 *change_attr != *attr_ref &&
2369 *change_attr != Attribute::LastModifiedCid
2371 })
2372 }
2373 State::Tombstone { at } => at == cid,
2374 }
2375 }
2376
2377 #[cfg(test)]
2381 pub(crate) fn into_invalid(mut self) -> Entry<EntryInvalid, STATE> {
2382 let cid = Cid::new_zero();
2383 self.set_last_changed(cid.clone());
2384
2385 let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
2386
2387 Entry {
2388 valid: EntryInvalid { cid, ecstate },
2389 state: self.state,
2390 attrs: self.attrs,
2391 }
2392 }
2393}
2394
2395impl GetUuid for Entry<EntryReduced, EntryCommitted> {
2396 fn get_uuid(&self) -> Uuid {
2397 self.valid.uuid
2398 }
2399}
2400
2401impl Entry<EntryReduced, EntryCommitted> {
2402 pub fn get_uuid(&self) -> Uuid {
2403 self.valid.uuid
2404 }
2405
2406 pub fn to_pe(&self, qs: &mut QueryServerReadTransaction) -> Result<ProtoEntry, OperationError> {
2408 let attrs: Result<_, _> = self
2410 .attrs
2411 .iter()
2412 .map(|(k, vs)| qs.resolve_valueset(vs).map(|pvs| (k.to_string(), pvs)))
2413 .collect();
2414 Ok(ProtoEntry { attrs: attrs? })
2415 }
2416
2417 pub fn to_scim_kanidm<'a, TXN>(
2418 &self,
2419 read_txn: &mut TXN,
2420 ) -> Result<ScimEntryKanidm, OperationError>
2421 where
2422 TXN: QueryServerTransaction<'a>,
2423 {
2424 let result: Result<BTreeMap<Attribute, ScimValueKanidm>, OperationError> = self
2425 .attrs
2426 .iter()
2427 .filter(|(k, _vs)| **k != Attribute::Uuid)
2429 .filter_map(|(k, vs)| {
2430 let opt_resolve_status = vs.to_scim_value();
2431 let res_opt_scim_value = match opt_resolve_status {
2432 None => Ok(None),
2433 Some(ScimResolveStatus::Resolved(scim_value_kani)) => Ok(Some(scim_value_kani)),
2434 Some(ScimResolveStatus::NeedsResolution(scim_value_interim)) => {
2435 read_txn.resolve_scim_interim(scim_value_interim)
2436 }
2437 };
2438 res_opt_scim_value
2439 .transpose()
2440 .map(|scim_res| scim_res.map(|scim_value| (k.clone(), scim_value)))
2441 })
2442 .collect();
2443
2444 let attrs = result?;
2445
2446 let ext_access_check = self.valid.effective_access.as_ref().map(|eff_acc| {
2447 let ident = eff_acc.ident;
2448 let delete = eff_acc.delete;
2449 let search = (&eff_acc.search).into();
2450 let modify_present = (&eff_acc.modify_pres).into();
2451 let modify_remove = (&eff_acc.modify_rem).into();
2452
2453 ScimEffectiveAccess {
2454 ident,
2455 delete,
2456 search,
2457 modify_present,
2458 modify_remove,
2459 }
2460 });
2461
2462 let id = self.get_uuid();
2463
2464 let schemas = Vec::with_capacity(0);
2467
2468 Ok(ScimEntryKanidm {
2469 header: ScimEntryHeader {
2470 schemas,
2471 id,
2472 external_id: None,
2474 meta: None,
2477 },
2478 ext_access_check,
2479 attrs,
2480 })
2481 }
2482
2483 pub fn to_ldap(
2485 &self,
2486 qs: &mut QueryServerReadTransaction,
2487 basedn: &str,
2488 all_attrs: bool,
2490 l_attrs: &[String],
2493 ) -> Result<LdapSearchResultEntry, OperationError> {
2494 let rdn = qs.uuid_to_rdn(self.get_uuid())?;
2495
2496 let dn = format!("{rdn},{basedn}");
2497
2498 let attr_map: Result<Map<&str, Vec<Vec<u8>>>, _> = self
2503 .attrs
2504 .iter()
2505 .map(|(k, vs)| {
2506 qs.resolve_valueset_ldap(vs, basedn)
2507 .map(|pvs| (k.as_str(), pvs))
2508 })
2509 .collect();
2510 let attr_map = attr_map?;
2511
2512 let attr_names: Vec<(&str, &str)> = if all_attrs {
2515 self.attrs
2517 .keys()
2518 .map(|k| (k.as_str(), k.as_str()))
2519 .chain(
2520 l_attrs
2521 .iter()
2522 .map(|k| (k.as_str(), ldap_vattr_map(k.as_str()).unwrap_or(k.as_str()))),
2523 )
2524 .collect()
2525 } else {
2526 l_attrs
2528 .iter()
2529 .map(|k| (k.as_str(), ldap_vattr_map(k.as_str()).unwrap_or(k.as_str())))
2530 .collect()
2531 };
2532
2533 let attributes: Vec<_> = attr_names
2535 .into_iter()
2536 .filter_map(|(ldap_a, kani_a)| {
2537 match ldap_a {
2539 LDAP_ATTR_DN => Some(LdapPartialAttribute {
2540 atype: LDAP_ATTR_DN.to_string(),
2541 vals: vec![dn.as_bytes().to_vec()],
2542 }),
2543 LDAP_ATTR_ENTRYDN => Some(LdapPartialAttribute {
2544 atype: LDAP_ATTR_ENTRYDN.to_string(),
2545 vals: vec![dn.as_bytes().to_vec()],
2546 }),
2547 LDAP_ATTR_MAIL_PRIMARY | LDAP_ATTR_EMAIL_PRIMARY => {
2548 attr_map.get(kani_a).map(|pvs| LdapPartialAttribute {
2549 atype: ldap_a.to_string(),
2550 vals: pvs
2551 .first()
2552 .map(|first| vec![first.clone()])
2553 .unwrap_or_default(),
2554 })
2555 }
2556 LDAP_ATTR_MAIL_ALTERNATIVE | LDAP_ATTR_EMAIL_ALTERNATIVE => {
2557 attr_map.get(kani_a).map(|pvs| LdapPartialAttribute {
2558 atype: ldap_a.to_string(),
2559 vals: pvs
2560 .split_first()
2561 .map(|(_, rest)| rest.to_vec())
2562 .unwrap_or_default(),
2563 })
2564 }
2565 ATTR_HOME_DIRECTORY => Some(LdapPartialAttribute {
2566 atype: ATTR_HOME_DIRECTORY.to_string(),
2567 vals: vec![format!("/home/{}", self.get_uuid()).into_bytes()],
2568 }),
2569 _ => attr_map.get(kani_a).map(|pvs| LdapPartialAttribute {
2570 atype: ldap_a.to_string(),
2571 vals: pvs.clone(),
2572 }),
2573 }
2574 })
2575 .collect();
2576
2577 Ok(LdapSearchResultEntry { dn, attributes })
2578 }
2579}
2580
2581impl<VALID, STATE> Entry<VALID, STATE> {
2582 fn add_ava_int(&mut self, attr: Attribute, value: Value) -> bool {
2587 if let Some(vs) = self.attrs.get_mut(&attr) {
2588 let r = vs.insert_checked(value);
2589 debug_assert!(r.is_ok());
2590 r.unwrap_or(false)
2592 } else {
2593 #[allow(clippy::expect_used)]
2594 let vs = valueset::from_value_iter(std::iter::once(value))
2595 .expect("Unable to fail - non-zero iter, and single value type!");
2596 self.attrs.insert(attr, vs);
2597 true
2599 }
2600 }
2602
2603 fn set_ava_iter_int<T>(&mut self, attr: Attribute, iter: T)
2605 where
2606 T: IntoIterator<Item = Value>,
2607 {
2608 let Ok(vs) = valueset::from_value_iter(iter.into_iter()) else {
2609 trace!("set_ava_iter_int - empty from_value_iter, skipping");
2610 return;
2611 };
2612
2613 if let Some(existing_vs) = self.attrs.get_mut(&attr) {
2614 let _ = existing_vs.merge(&vs);
2616 } else {
2617 self.attrs.insert(attr, vs);
2619 }
2620 }
2621
2622 #[cfg(test)]
2624 fn set_last_changed(&mut self, cid: Cid) {
2625 let cv = vs_cid![cid.clone()];
2626 let _ = self.attrs.insert(Attribute::LastModifiedCid, cv);
2627 let cv = vs_cid![cid];
2628 let _ = self.attrs.insert(Attribute::CreatedAtCid, cv);
2629 }
2630
2631 pub(crate) fn get_display_id(&self) -> String {
2632 self.attrs
2633 .get(&Attribute::Spn)
2634 .and_then(|vs| vs.to_value_single())
2635 .or_else(|| {
2636 self.attrs
2637 .get(&Attribute::Name)
2638 .and_then(|vs| vs.to_value_single())
2639 })
2640 .or_else(|| {
2641 self.attrs
2642 .get(&Attribute::Uuid)
2643 .and_then(|vs| vs.to_value_single())
2644 })
2645 .map(|value| value.to_proto_string_clone())
2646 .unwrap_or_else(|| "no entry id available".to_string())
2647 }
2648
2649 pub fn has_class(&self, class: &EntryClass) -> bool {
2650 self.get_ava_set(Attribute::Class)
2651 .and_then(|vs| vs.as_iutf8_set())
2652 .map(|set| {
2653 let class_name: &str = class.into();
2654 set.contains(class_name)
2655 })
2656 .unwrap_or_default()
2657 }
2658
2659 pub fn attr_keys(&self) -> impl Iterator<Item = &Attribute> {
2660 self.attrs.keys()
2661 }
2662
2663 pub fn get_ava_names(&self) -> impl Iterator<Item = &str> {
2665 self.attrs.keys().map(|a| a.as_str())
2667 }
2668
2669 pub fn get_ava(&self) -> &Eattrs {
2671 &self.attrs
2672 }
2673
2674 pub fn get_ava_iter(&self) -> impl Iterator<Item = (&Attribute, &ValueSet)> {
2675 self.attrs.iter()
2676 }
2677
2678 pub fn get_ava_set<A: AsRef<Attribute>>(&self, attr: A) -> Option<&ValueSet> {
2680 self.attrs.get(attr.as_ref())
2681 }
2682
2683 pub fn get_ava_refer<A: AsRef<Attribute>>(&self, attr: A) -> Option<&BTreeSet<Uuid>> {
2684 self.get_ava_set(attr).and_then(|vs| vs.as_refer_set())
2685 }
2686
2687 pub fn get_ava_as_iutf8_iter<A: AsRef<Attribute>>(
2688 &self,
2689 attr: A,
2690 ) -> Option<impl Iterator<Item = &str>> {
2691 self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_iter())
2692 }
2693
2694 pub fn get_ava_as_iutf8<A: AsRef<Attribute>>(&self, attr: A) -> Option<&BTreeSet<String>> {
2695 self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_set())
2696 }
2697
2698 pub fn get_ava_as_image<A: AsRef<Attribute>>(&self, attr: A) -> Option<&HashSet<ImageValue>> {
2699 self.get_ava_set(attr).and_then(|vs| vs.as_imageset())
2700 }
2701
2702 pub fn get_ava_single_image<A: AsRef<Attribute>>(&self, attr: A) -> Option<ImageValue> {
2703 let images = self.get_ava_set(attr).and_then(|vs| vs.as_imageset())?;
2704 images.iter().next().cloned()
2705 }
2706
2707 pub fn get_ava_single_credential_type<A: AsRef<Attribute>>(
2708 &self,
2709 attr: A,
2710 ) -> Option<CredentialType> {
2711 self.get_ava_set(attr)
2712 .and_then(|vs| vs.to_credentialtype_single())
2713 }
2714
2715 pub fn get_ava_as_oauthscopes<A: AsRef<Attribute>>(
2716 &self,
2717 attr: A,
2718 ) -> Option<impl Iterator<Item = &str>> {
2719 self.get_ava_set(attr)
2720 .and_then(|vs| vs.as_oauthscope_iter())
2721 }
2722
2723 pub fn get_ava_as_oauthscopemaps<A: AsRef<Attribute>>(
2724 &self,
2725 attr: A,
2726 ) -> Option<&std::collections::BTreeMap<Uuid, std::collections::BTreeSet<String>>> {
2727 self.get_ava_set(attr).and_then(|vs| vs.as_oauthscopemap())
2728 }
2729
2730 pub fn get_ava_as_intenttokens<A: AsRef<Attribute>>(
2731 &self,
2732 attr: A,
2733 ) -> Option<&std::collections::BTreeMap<String, IntentTokenState>> {
2734 self.get_ava_set(attr)
2735 .and_then(|vs| vs.as_intenttoken_map())
2736 }
2737
2738 pub fn get_ava_as_session_map<A: AsRef<Attribute>>(
2739 &self,
2740 attr: A,
2741 ) -> Option<&std::collections::BTreeMap<Uuid, Session>> {
2742 self.get_ava_set(attr).and_then(|vs| vs.as_session_map())
2743 }
2744
2745 pub fn get_ava_as_apitoken_map<A: AsRef<Attribute>>(
2746 &self,
2747 attr: A,
2748 ) -> Option<&std::collections::BTreeMap<Uuid, ApiToken>> {
2749 self.get_ava_set(attr).and_then(|vs| vs.as_apitoken_map())
2750 }
2751
2752 pub fn get_ava_as_oauth2session_map<A: AsRef<Attribute>>(
2753 &self,
2754 attr: A,
2755 ) -> Option<&std::collections::BTreeMap<Uuid, Oauth2Session>> {
2756 self.get_ava_set(attr)
2757 .and_then(|vs| vs.as_oauth2session_map())
2758 }
2759
2760 pub fn get_ava_as_s256_set<A: AsRef<Attribute>>(
2761 &self,
2762 attr: A,
2763 ) -> Option<&std::collections::BTreeSet<Sha256Output>> {
2764 self.get_ava_set(attr).and_then(|vs| vs.as_s256_set())
2765 }
2766
2767 pub fn get_ava_iter_iname<A: AsRef<Attribute>>(
2769 &self,
2770 attr: A,
2771 ) -> Option<impl Iterator<Item = &str>> {
2772 self.get_ava_set(attr).and_then(|vs| vs.as_iname_iter())
2773 }
2774
2775 pub fn get_ava_iter_iutf8<A: AsRef<Attribute>>(
2777 &self,
2778 attr: A,
2779 ) -> Option<impl Iterator<Item = &str>> {
2780 self.get_ava_set(attr).and_then(|vs| vs.as_iutf8_iter())
2781 }
2782
2783 pub fn get_ava_as_refuuid<A: AsRef<Attribute>>(
2785 &self,
2786 attr: A,
2787 ) -> Option<Box<dyn Iterator<Item = Uuid> + '_>> {
2788 self.get_ava_set(attr).and_then(|vs| vs.as_ref_uuid_iter())
2790 }
2791
2792 pub fn get_ava_iter_sshpubkeys<A: AsRef<Attribute>>(
2794 &self,
2795 attr: A,
2796 ) -> Option<impl Iterator<Item = String> + '_> {
2797 self.get_ava_set(attr)
2798 .and_then(|vs| vs.as_sshpubkey_string_iter())
2799 }
2800
2801 pub fn get_ava_single<A: AsRef<Attribute>>(&self, attr: A) -> Option<Value> {
2807 self.get_ava_set(attr).and_then(|vs| vs.to_value_single())
2808 }
2809
2810 pub fn get_ava_single_proto_string<A: AsRef<Attribute>>(&self, attr: A) -> Option<String> {
2811 self.get_ava_set(attr)
2812 .and_then(|vs| vs.to_proto_string_single())
2813 }
2814
2815 pub fn get_ava_single_bool<A: AsRef<Attribute>>(&self, attr: A) -> Option<bool> {
2817 self.get_ava_set(attr).and_then(|vs| vs.to_bool_single())
2818 }
2819
2820 pub fn get_ava_single_uint32<A: AsRef<Attribute>>(&self, attr: A) -> Option<u32> {
2822 self.get_ava_set(attr).and_then(|vs| vs.to_uint32_single())
2823 }
2824
2825 pub fn get_ava_single_syntax<A: AsRef<Attribute>>(&self, attr: A) -> Option<SyntaxType> {
2827 self.get_ava_set(attr)
2828 .and_then(|vs| vs.to_syntaxtype_single())
2829 }
2830
2831 pub fn get_ava_single_credential<A: AsRef<Attribute>>(&self, attr: A) -> Option<&Credential> {
2833 self.get_ava_set(attr)
2834 .and_then(|vs| vs.to_credential_single())
2835 }
2836
2837 pub fn get_ava_passkeys<A: AsRef<Attribute>>(
2839 &self,
2840 attr: A,
2841 ) -> Option<&BTreeMap<Uuid, (String, PasskeyV4)>> {
2842 self.get_ava_set(attr).and_then(|vs| vs.as_passkey_map())
2843 }
2844
2845 pub fn get_ava_attestedpasskeys<A: AsRef<Attribute>>(
2847 &self,
2848 attr: A,
2849 ) -> Option<&BTreeMap<Uuid, (String, AttestedPasskeyV4)>> {
2850 self.get_ava_set(attr)
2851 .and_then(|vs| vs.as_attestedpasskey_map())
2852 }
2853
2854 pub fn get_ava_uihint<A: AsRef<Attribute>>(&self, attr: A) -> Option<&BTreeSet<UiHint>> {
2856 self.get_ava_set(attr).and_then(|vs| vs.as_uihint_set())
2857 }
2858
2859 pub fn get_ava_single_secret<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2861 self.get_ava_set(attr).and_then(|vs| vs.to_secret_single())
2862 }
2863
2864 pub fn get_ava_single_datetime<A: AsRef<Attribute>>(&self, attr: A) -> Option<OffsetDateTime> {
2866 self.get_ava_set(attr)
2867 .and_then(|vs| vs.to_datetime_single())
2868 }
2869
2870 pub(crate) fn get_ava_single_utf8<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2872 self.get_ava_set(attr).and_then(|vs| vs.to_utf8_single())
2873 }
2874
2875 pub(crate) fn get_ava_single_iutf8<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2877 self.get_ava_set(attr).and_then(|vs| vs.to_iutf8_single())
2878 }
2879
2880 pub(crate) fn get_ava_single_iname<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2882 self.get_ava_set(attr).and_then(|vs| vs.to_iname_single())
2883 }
2884
2885 pub fn get_ava_single_url<A: AsRef<Attribute>>(&self, attr: A) -> Option<&Url> {
2887 self.get_ava_set(attr).and_then(|vs| vs.to_url_single())
2888 }
2889
2890 pub fn get_ava_single_uuid<A: AsRef<Attribute>>(&self, attr: A) -> Option<Uuid> {
2891 self.get_ava_set(attr).and_then(|vs| vs.to_uuid_single())
2892 }
2893
2894 pub fn get_ava_single_refer<A: AsRef<Attribute>>(&self, attr: A) -> Option<Uuid> {
2895 self.get_ava_set(attr).and_then(|vs| vs.to_refer_single())
2896 }
2897
2898 pub fn get_ava_mail_primary<A: AsRef<Attribute>>(&self, attr: A) -> Option<&str> {
2899 self.get_ava_set(attr)
2900 .and_then(|vs| vs.to_email_address_primary_str())
2901 }
2902
2903 pub fn get_ava_iter_mail<A: AsRef<Attribute>>(
2904 &self,
2905 attr: A,
2906 ) -> Option<impl Iterator<Item = &str>> {
2907 self.get_ava_set(attr).and_then(|vs| vs.as_email_str_iter())
2908 }
2909
2910 pub fn get_ava_single_protofilter<A: AsRef<Attribute>>(&self, attr: A) -> Option<&ProtoFilter> {
2912 self.get_ava_set(attr)
2913 .and_then(|vs| vs.to_json_filter_single())
2914 }
2915
2916 pub fn get_ava_single_private_binary<A: AsRef<Attribute>>(&self, attr: A) -> Option<&[u8]> {
2917 self.get_ava_set(attr)
2918 .and_then(|vs| vs.to_private_binary_single())
2919 }
2920
2921 pub fn get_ava_single_jws_key_es256<A: AsRef<Attribute>>(
2922 &self,
2923 attr: A,
2924 ) -> Option<&JwsEs256Signer> {
2925 self.get_ava_set(attr)
2926 .and_then(|vs| vs.to_jws_key_es256_single())
2927 }
2928
2929 pub fn get_ava_single_eckey_private<A: AsRef<Attribute>>(
2930 &self,
2931 attr: A,
2932 ) -> Option<&EcKey<Private>> {
2933 self.get_ava_set(attr)
2934 .and_then(|vs| vs.to_eckey_private_single())
2935 }
2936
2937 pub fn get_ava_single_eckey_public<A: AsRef<Attribute>>(
2938 &self,
2939 attr: A,
2940 ) -> Option<&EcKey<Public>> {
2941 self.get_ava_set(attr)
2942 .and_then(|vs| vs.to_eckey_public_single())
2943 }
2944
2945 pub fn get_ava_webauthn_attestation_ca_list<A: AsRef<Attribute>>(
2946 &self,
2947 attr: A,
2948 ) -> Option<&AttestationCaList> {
2949 self.get_ava_set(attr)
2950 .and_then(|vs| vs.as_webauthn_attestation_ca_list())
2951 }
2952
2953 pub fn get_ava_application_password<A: AsRef<Attribute>>(
2954 &self,
2955 attr: A,
2956 ) -> Option<&BTreeMap<Uuid, Vec<ApplicationPassword>>> {
2957 self.get_ava_set(attr)
2958 .and_then(|vs| vs.as_application_password_map())
2959 }
2960
2961 pub(crate) fn generate_spn(&self, domain_name: &str) -> Option<ValueSet> {
2963 if let Some(name) = self.get_ava_single_iname(Attribute::Name) {
2964 return Some(ValueSetSpn::new((name.into(), domain_name.into())));
2966 }
2967
2968 let spn_set = self.get_ava_set(Attribute::Spn)?;
2970
2971 if spn_set.syntax() == SyntaxType::SecurityPrincipalName {
2972 Some(spn_set.clone())
2974 } else if let Some(name) = spn_set.to_iname_single() {
2975 Some(ValueSetSpn::new((name.into(), domain_name.into())))
2977 } else {
2978 None
2980 }
2981 }
2982
2983 pub fn attribute_pres<A: AsRef<Attribute>>(&self, attr: A) -> bool {
2985 self.attrs.contains_key(attr.as_ref())
2986 }
2987
2988 pub fn attribute_equality<A: AsRef<Attribute>>(&self, attr: A, value: &PartialValue) -> bool {
2991 match self.attrs.get(attr.as_ref()) {
2996 Some(v_list) => v_list.contains(value),
2997 None => false,
2998 }
2999 }
3000
3001 pub fn attribute_substring<A: AsRef<Attribute>>(
3004 &self,
3005 attr: A,
3006 subvalue: &PartialValue,
3007 ) -> bool {
3008 self.get_ava_set(attr)
3009 .map(|vset| vset.substring(subvalue))
3010 .unwrap_or(false)
3011 }
3012
3013 pub fn attribute_startswith<A: AsRef<Attribute>>(
3016 &self,
3017 attr: A,
3018 subvalue: &PartialValue,
3019 ) -> bool {
3020 self.get_ava_set(attr)
3021 .map(|vset| vset.startswith(subvalue))
3022 .unwrap_or(false)
3023 }
3024
3025 pub fn attribute_endswith<A: AsRef<Attribute>>(
3028 &self,
3029 attr: A,
3030 subvalue: &PartialValue,
3031 ) -> bool {
3032 self.get_ava_set(attr)
3033 .map(|vset| vset.endswith(subvalue))
3034 .unwrap_or(false)
3035 }
3036
3037 pub fn attribute_lessthan<A: AsRef<Attribute>>(
3040 &self,
3041 attr: A,
3042 subvalue: &PartialValue,
3043 ) -> bool {
3044 self.get_ava_set(attr)
3045 .map(|vset| vset.lessthan(subvalue))
3046 .unwrap_or(false)
3047 }
3048
3049 #[inline(always)]
3054 #[instrument(level = "trace", name = "entry::entry_match_no_index", skip(self))]
3055 pub fn entry_match_no_index(&self, filter: &Filter<FilterValidResolved>) -> bool {
3057 self.entry_match_no_index_inner(filter.to_inner())
3058 }
3059
3060 fn entry_match_no_index_inner(&self, filter: &FilterResolved) -> bool {
3064 match filter {
3067 FilterResolved::Eq(attr, value, _) => self.attribute_equality(attr, value),
3068 FilterResolved::Cnt(attr, subvalue, _) => self.attribute_substring(attr, subvalue),
3069 FilterResolved::Stw(attr, subvalue, _) => self.attribute_startswith(attr, subvalue),
3070 FilterResolved::Enw(attr, subvalue, _) => self.attribute_endswith(attr, subvalue),
3071 FilterResolved::Pres(attr, _) => self.attribute_pres(attr),
3072 FilterResolved::LessThan(attr, subvalue, _) => self.attribute_lessthan(attr, subvalue),
3073 FilterResolved::Or(l, _) => l.iter().any(|f| self.entry_match_no_index_inner(f)),
3075 FilterResolved::And(l, _) => l.iter().all(|f| self.entry_match_no_index_inner(f)),
3077 FilterResolved::Inclusion(_, _) => {
3078 false
3082 }
3083 FilterResolved::AndNot(f, _) => !self.entry_match_no_index_inner(f),
3084 FilterResolved::Invalid(_) => false,
3085 }
3086 }
3087
3088 pub fn filter_from_attrs(&self, attrs: &[Attribute]) -> Option<Filter<FilterInvalid>> {
3091 let mut pairs: Vec<(Attribute, PartialValue)> = Vec::with_capacity(0);
3103
3104 for attr in attrs {
3105 match self.attrs.get(attr) {
3106 Some(values) => values
3107 .to_partialvalue_iter()
3108 .for_each(|pv| pairs.push((attr.clone(), pv))),
3109 None => return None,
3110 }
3111 }
3112
3113 let res: Vec<FC> = pairs
3114 .into_iter()
3115 .map(|(attr, pv)| FC::Eq(attr, pv))
3116 .collect();
3117 Some(filter_all!(f_and(res)))
3118 }
3119
3120 pub fn gen_modlist_assert(
3123 &self,
3124 schema: &dyn SchemaTransaction,
3125 ) -> Result<ModifyList<ModifyInvalid>, SchemaError> {
3126 let mut mods = ModifyList::new();
3130
3131 for (k, vs) in self.attrs.iter() {
3132 if *k == Attribute::Uuid {
3148 continue;
3149 }
3150 match schema.is_multivalue(k) {
3152 Ok(r) => {
3153 if !r ||
3156 *k == Attribute::AcpReceiverGroup ||
3159 *k == Attribute::AcpCreateAttr ||
3160 *k == Attribute::AcpCreateClass ||
3161 *k == Attribute::AcpModifyPresentAttr ||
3162 *k == Attribute::AcpModifyRemovedAttr ||
3163 *k == Attribute::AcpModifyClass ||
3164 *k == Attribute::SystemMust ||
3165 *k == Attribute::SystemMay
3166 {
3167 mods.push_mod(Modify::Purged(k.clone()));
3168 }
3169 }
3170 Err(e) => return Err(e),
3172 }
3173 for v in vs.to_value_iter() {
3174 mods.push_mod(Modify::Present(k.clone(), v.clone()));
3175 }
3176 }
3177
3178 Ok(mods)
3179 }
3180
3181 pub fn mask_recycled_ts(&self) -> Option<&Self> {
3184 match self.attrs.get(&Attribute::Class) {
3186 Some(cls) => {
3187 if cls.contains(&EntryClass::Tombstone.to_partialvalue())
3188 || cls.contains(&EntryClass::Recycled.to_partialvalue())
3189 {
3190 None
3191 } else {
3192 Some(self)
3193 }
3194 }
3195 None => Some(self),
3196 }
3197 }
3198
3199 pub fn mask_recycled(&self) -> Option<&Self> {
3202 match self.attrs.get(&Attribute::Class) {
3204 Some(cls) => {
3205 if cls.contains(&EntryClass::Recycled.to_partialvalue()) {
3206 None
3207 } else {
3208 Some(self)
3209 }
3210 }
3211 None => Some(self),
3212 }
3213 }
3214
3215 pub fn mask_tombstone(&self) -> Option<&Self> {
3218 match self.attrs.get(&Attribute::Class) {
3220 Some(cls) => {
3221 if cls.contains(&EntryClass::Tombstone.to_partialvalue()) {
3222 None
3223 } else {
3224 Some(self)
3225 }
3226 }
3227 None => Some(self),
3228 }
3229 }
3230}
3231
3232impl<STATE> Entry<EntryInvalid, STATE>
3233where
3234 STATE: Clone,
3235{
3236 pub fn add_ava(&mut self, attr: Attribute, value: Value) {
3241 self.valid.ecstate.change_ava(&self.valid.cid, &attr);
3242 self.add_ava_int(attr, value);
3243 }
3244
3245 pub fn add_ava_if_not_exist<A: AsRef<Attribute>>(&mut self, attr: A, value: Value) {
3246 let attr_ref = attr.as_ref();
3247 if self.add_ava_int(attr_ref.clone(), value) {
3249 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3251 }
3252 }
3253
3254 fn assert_ava<A: AsRef<Attribute>>(
3255 &mut self,
3256 attr: A,
3257 value: &PartialValue,
3258 ) -> Result<(), OperationError> {
3259 self.valid
3260 .ecstate
3261 .change_ava(&self.valid.cid, attr.as_ref());
3262
3263 if self.attribute_equality(attr, value) {
3264 Ok(())
3265 } else {
3266 Err(OperationError::ModifyAssertionFailed)
3267 }
3268 }
3269
3270 pub(crate) fn remove_ava<A: AsRef<Attribute>>(&mut self, attr: A, value: &PartialValue) {
3273 let attr_ref = attr.as_ref();
3274 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3275
3276 let rm = if let Some(vs) = self.attrs.get_mut(attr_ref) {
3277 vs.remove(value, &self.valid.cid);
3278 vs.is_empty()
3279 } else {
3280 false
3281 };
3282 if rm {
3283 self.attrs.remove(attr_ref);
3284 };
3285 }
3286
3287 pub(crate) fn remove_avas<A: AsRef<Attribute>>(
3288 &mut self,
3289 attr: A,
3290 values: &BTreeSet<PartialValue>,
3291 ) {
3292 let attr_ref = attr.as_ref();
3293 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3294
3295 let rm = if let Some(vs) = self.attrs.get_mut(attr_ref) {
3296 values.iter().for_each(|k| {
3297 vs.remove(k, &self.valid.cid);
3298 });
3299 vs.is_empty()
3300 } else {
3301 false
3302 };
3303 if rm {
3304 self.attrs.remove(attr_ref);
3305 };
3306 }
3307
3308 pub(crate) fn purge_ava<A: AsRef<Attribute>>(&mut self, attr: A) {
3311 let attr_ref = attr.as_ref();
3312 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3313 let can_remove = self
3316 .attrs
3317 .get_mut(attr_ref)
3318 .map(|vs| vs.purge(&self.valid.cid))
3319 .unwrap_or_default();
3321 if can_remove {
3322 self.attrs.remove(attr_ref);
3323 }
3324 }
3325
3326 pub fn pop_ava<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<ValueSet> {
3328 let attr_ref = attr.as_ref();
3329 self.valid.ecstate.change_ava(&self.valid.cid, attr_ref);
3330
3331 let mut vs = self.attrs.remove(attr_ref)?;
3332 if vs.purge(&self.valid.cid) {
3333 Some(vs)
3335 } else {
3336 let r_vs = vs.clone();
3338 self.attrs.insert(attr_ref.clone(), vs);
3339 Some(r_vs)
3340 }
3341 }
3342
3343 #[cfg(test)]
3348 pub(crate) fn force_trim_ava<A: AsRef<Attribute>>(&mut self, attr: A) -> Option<ValueSet> {
3349 self.valid
3350 .ecstate
3351 .change_ava(&self.valid.cid, attr.as_ref());
3352 self.attrs.remove(attr.as_ref())
3353 }
3354
3355 pub fn set_ava<T>(&mut self, attr: &Attribute, iter: T)
3358 where
3359 T: Clone + IntoIterator<Item = Value>,
3360 {
3361 self.purge_ava(attr);
3362 self.set_ava_iter_int(attr.clone(), iter)
3363 }
3364
3365 pub fn set_ava_set(&mut self, attr: &Attribute, vs: ValueSet) {
3368 self.purge_ava(attr);
3369 if let Some(existing_vs) = self.attrs.get_mut(attr) {
3370 let _ = existing_vs.merge(&vs);
3371 } else {
3372 self.attrs.insert(attr.clone(), vs);
3373 }
3374 }
3375
3376 pub fn merge_ava_set(&mut self, attr: &Attribute, vs: ValueSet) -> Result<(), OperationError> {
3379 self.valid.ecstate.change_ava(&self.valid.cid, attr);
3380 if let Some(existing_vs) = self.attrs.get_mut(attr) {
3381 existing_vs.merge(&vs)
3382 } else {
3383 self.attrs.insert(attr.clone(), vs);
3384 Ok(())
3385 }
3386 }
3387
3388 pub fn apply_modlist(
3390 &mut self,
3391 modlist: &ModifyList<ModifyValid>,
3392 ) -> Result<(), OperationError> {
3393 for modify in modlist {
3394 match modify {
3395 Modify::Present(attr, value) => {
3396 self.add_ava(attr.clone(), value.clone());
3397 }
3398 Modify::Removed(attr, value) => {
3399 self.remove_ava(attr, value);
3400 }
3401 Modify::Purged(attr) => {
3402 self.purge_ava(attr);
3403 }
3404 Modify::Assert(attr, value) => {
3405 self.assert_ava(attr, value).inspect_err(|_e| {
3406 error!("Modification assertion was not met. {} {:?}", attr, value);
3407 })?;
3408 }
3409 Modify::Set(attr, valueset) => self.set_ava_set(attr, valueset.clone()),
3410 }
3411 }
3412 Ok(())
3413 }
3414}
3415
3416impl<VALID, STATE> PartialEq for Entry<VALID, STATE> {
3417 fn eq(&self, rhs: &Entry<VALID, STATE>) -> bool {
3418 compare_attrs(&self.attrs, &rhs.attrs)
3429 }
3430}
3431
3432pub(crate) fn entry_init_fn<T>(args: T) -> EntryInitNew
3434where
3435 T: IntoIterator<Item = (Attribute, Value)>,
3436{
3437 let mut entry: EntryInitNew = Entry::new();
3438 args.into_iter().for_each(|(k, v)| entry.add_ava(k, v));
3439 entry
3440}
3441
3442#[cfg(test)]
3443mod tests {
3444 use crate::prelude::*;
3445 use std::collections::BTreeSet as Set;
3446
3447 use hashbrown::HashMap;
3448
3449 use crate::be::{IdxKey, IdxSlope};
3450 use crate::entry::{Entry, EntryInit, EntryInvalid, EntryNew};
3451 use crate::modify::{Modify, ModifyList};
3452 use crate::value::{IndexType, PartialValue, Value};
3453
3454 #[test]
3455 fn test_entry_basic() {
3456 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3457
3458 e.add_ava(Attribute::UserId, Value::from("william"));
3459 }
3460
3461 #[test]
3462 fn test_entry_dup_value() {
3463 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3470 e.add_ava(Attribute::UserId, Value::from("william"));
3471 e.add_ava(Attribute::UserId, Value::from("william"));
3472
3473 let values = e.get_ava_set(Attribute::UserId).expect("Failed to get ava");
3474 assert_eq!(values.len(), 1)
3476 }
3477
3478 #[test]
3479 fn test_entry_pres() {
3480 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3481 e.add_ava(Attribute::UserId, Value::from("william"));
3482
3483 assert!(e.attribute_pres(Attribute::UserId));
3484 assert!(!e.attribute_pres(Attribute::Name));
3485 }
3486
3487 #[test]
3488 fn test_entry_equality() {
3489 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3490
3491 e.add_ava(Attribute::UserId, Value::from("william"));
3492
3493 assert!(e.attribute_equality(Attribute::UserId, &PartialValue::new_utf8s("william")));
3494 assert!(!e.attribute_equality(Attribute::UserId, &PartialValue::new_utf8s("test")));
3495 assert!(!e.attribute_equality(Attribute::NonExist, &PartialValue::new_utf8s("william")));
3496 assert!(!e.attribute_equality(Attribute::UserId, &PartialValue::new_iutf8("william")));
3498 }
3499
3500 #[test]
3501 fn test_entry_substring() {
3502 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3503
3504 e.add_ava(Attribute::UserId, Value::from("william"));
3505
3506 assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("william")));
3507 assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("will")));
3508 assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("liam")));
3509 assert!(e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("lli")));
3510 assert!(!e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("llim")));
3511 assert!(!e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("bob")));
3512 assert!(!e.attribute_substring(Attribute::UserId, &PartialValue::new_utf8s("wl")));
3513
3514 assert!(e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("will")));
3515 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("liam")));
3516 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("lli")));
3517 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("llim")));
3518 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("bob")));
3519 assert!(!e.attribute_startswith(Attribute::UserId, &PartialValue::new_utf8s("wl")));
3520
3521 assert!(e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("liam")));
3522 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("will")));
3523 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("lli")));
3524 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("llim")));
3525 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("bob")));
3526 assert!(!e.attribute_endswith(Attribute::UserId, &PartialValue::new_utf8s("wl")));
3527 }
3528
3529 #[test]
3530 fn test_entry_lessthan() {
3531 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3532
3533 let pv2 = PartialValue::new_uint32(2);
3534 let pv8 = PartialValue::new_uint32(8);
3535 let pv10 = PartialValue::new_uint32(10);
3536 let pv15 = PartialValue::new_uint32(15);
3537
3538 e1.add_ava(Attribute::TestAttr, Value::new_uint32(10));
3539
3540 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv2));
3541 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv8));
3542 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv10));
3543 assert!(e1.attribute_lessthan(Attribute::TestAttr, &pv15));
3544
3545 e1.add_ava(Attribute::TestAttr, Value::new_uint32(8));
3546
3547 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv2));
3548 assert!(!e1.attribute_lessthan(Attribute::TestAttr, &pv8));
3549 assert!(e1.attribute_lessthan(Attribute::TestAttr, &pv10));
3550 assert!(e1.attribute_lessthan(Attribute::TestAttr, &pv15));
3551 }
3552
3553 #[test]
3554 fn test_entry_apply_modlist() {
3555 let mut e: Entry<EntryInvalid, EntryNew> = Entry::new().into_invalid_new();
3557
3558 e.add_ava(Attribute::UserId, Value::from("william"));
3559
3560 let present_single_mods = ModifyList::new_valid_list(vec![Modify::Present(
3561 Attribute::Attr,
3562 Value::new_iutf8("value"),
3563 )]);
3564
3565 assert!(e.apply_modlist(&present_single_mods).is_ok());
3566
3567 assert!(e.attribute_equality(Attribute::UserId, &PartialValue::new_utf8s("william")));
3569 assert!(e.attribute_equality(Attribute::Attr, &PartialValue::new_iutf8("value")));
3570
3571 let present_multivalue_mods = ModifyList::new_valid_list(vec![
3573 Modify::Present(Attribute::Class, Value::new_iutf8("test")),
3574 Modify::Present(Attribute::Class, Value::new_iutf8("multi_test")),
3575 ]);
3576
3577 assert!(e.apply_modlist(&present_multivalue_mods).is_ok());
3578
3579 assert!(e.attribute_equality(Attribute::Class, &PartialValue::new_iutf8("test")));
3580 assert!(e.attribute_equality(Attribute::Class, &PartialValue::new_iutf8("multi_test")));
3581
3582 let purge_single_mods = ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Attr)]);
3584
3585 assert!(e.apply_modlist(&purge_single_mods).is_ok());
3586
3587 assert!(!e.attribute_pres(Attribute::Attr));
3588
3589 let purge_multi_mods = ModifyList::new_valid_list(vec![Modify::Purged(Attribute::Class)]);
3590
3591 assert!(e.apply_modlist(&purge_multi_mods).is_ok());
3592
3593 assert!(!e.attribute_pres(Attribute::Class));
3594
3595 let purge_empty_mods = purge_single_mods;
3596
3597 assert!(e.apply_modlist(&purge_empty_mods).is_ok());
3598
3599 let remove_mods = ModifyList::new_valid_list(vec![Modify::Removed(
3601 Attribute::Attr,
3602 PartialValue::new_iutf8("value"),
3603 )]);
3604
3605 assert!(e.apply_modlist(&present_single_mods).is_ok());
3606 assert!(e.attribute_equality(Attribute::Attr, &PartialValue::new_iutf8("value")));
3607 assert!(e.apply_modlist(&remove_mods).is_ok());
3608 assert!(!e.attrs.contains_key(&Attribute::Attr));
3609
3610 let remove_empty_mods = remove_mods;
3611
3612 assert!(e.apply_modlist(&remove_empty_mods).is_ok());
3613
3614 assert!(!e.attrs.contains_key(&Attribute::Attr));
3615 }
3616
3617 #[test]
3618 fn test_entry_idx_diff() {
3619 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3620 e1.add_ava(Attribute::UserId, Value::from("william"));
3621 let mut e1_mod = e1.clone();
3622 e1_mod.add_ava(Attribute::Extra, Value::from("test"));
3623
3624 let e1 = e1.into_sealed_committed();
3625 let e1_mod = e1_mod.into_sealed_committed();
3626
3627 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3628 e2.add_ava(Attribute::UserId, Value::from("claire"));
3629 let e2 = e2.into_sealed_committed();
3630
3631 let mut idxmeta = HashMap::with_capacity(8);
3632 idxmeta.insert(
3633 IdxKey {
3634 attr: Attribute::UserId,
3635 itype: IndexType::Equality,
3636 },
3637 IdxSlope::MAX,
3638 );
3639 idxmeta.insert(
3640 IdxKey {
3641 attr: Attribute::UserId,
3642 itype: IndexType::Presence,
3643 },
3644 IdxSlope::MAX,
3645 );
3646 idxmeta.insert(
3647 IdxKey {
3648 attr: Attribute::Extra,
3649 itype: IndexType::Equality,
3650 },
3651 IdxSlope::MAX,
3652 );
3653
3654 let r1 = Entry::idx_diff(&idxmeta, None, None);
3656 eprintln!("{r1:?}");
3657 assert_eq!(r1, Vec::with_capacity(0));
3658
3659 let mut del_r = Entry::idx_diff(&idxmeta, Some(&e1), None);
3661 del_r.sort_unstable();
3662 eprintln!("del_r {del_r:?}");
3663 assert!(
3664 del_r[0]
3665 == Err((
3666 &Attribute::UserId,
3667 IndexType::Equality,
3668 "william".to_string()
3669 ))
3670 );
3671 assert!(del_r[1] == Err((&Attribute::UserId, IndexType::Presence, "_".to_string())));
3672
3673 let mut add_r = Entry::idx_diff(&idxmeta, None, Some(&e1));
3675 add_r.sort_unstable();
3676 eprintln!("{add_r:?}");
3677 assert!(
3678 add_r[0]
3679 == Ok((
3680 &Attribute::UserId,
3681 IndexType::Equality,
3682 "william".to_string()
3683 ))
3684 );
3685 assert!(add_r[1] == Ok((&Attribute::UserId, IndexType::Presence, "_".to_string())));
3686
3687 let no_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e1));
3691 assert!(no_r.is_empty());
3692
3693 let add_a_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e1_mod));
3695 assert!(add_a_r[0] == Ok((&Attribute::Extra, IndexType::Equality, "test".to_string())));
3696
3697 let del_a_r = Entry::idx_diff(&idxmeta, Some(&e1_mod), Some(&e1));
3699 assert!(del_a_r[0] == Err((&Attribute::Extra, IndexType::Equality, "test".to_string())));
3700
3701 let mut chg_r = Entry::idx_diff(&idxmeta, Some(&e1), Some(&e2));
3703 chg_r.sort_unstable();
3704 eprintln!("{chg_r:?}");
3705 assert!(
3706 chg_r[1]
3707 == Err((
3708 &Attribute::UserId,
3709 IndexType::Equality,
3710 "william".to_string()
3711 ))
3712 );
3713
3714 assert!(
3715 chg_r[0]
3716 == Ok((
3717 &Attribute::UserId,
3718 IndexType::Equality,
3719 "claire".to_string()
3720 ))
3721 );
3722 }
3723
3724 #[test]
3725 fn test_entry_mask_recycled_ts() {
3726 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3727 e1.add_ava(Attribute::Class, EntryClass::Person.to_value());
3728 let e1 = e1.into_sealed_committed();
3729 assert!(e1.mask_recycled_ts().is_some());
3730
3731 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3732 e2.add_ava(Attribute::Class, EntryClass::Person.to_value());
3733 e2.add_ava(Attribute::Class, EntryClass::Recycled.into());
3734 let e2 = e2.into_sealed_committed();
3735 assert!(e2.mask_recycled_ts().is_none());
3736
3737 let mut e3: Entry<EntryInit, EntryNew> = Entry::new();
3738 e3.add_ava(Attribute::Class, EntryClass::Tombstone.into());
3739 let e3 = e3.into_sealed_committed();
3740 assert!(e3.mask_recycled_ts().is_none());
3741 }
3742
3743 #[test]
3744 fn test_entry_idx_name2uuid_diff() {
3745 let r = Entry::idx_name2uuid_diff(None, None);
3747 assert_eq!(r, (None, None));
3748
3749 {
3751 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3752 e.add_ava(Attribute::Class, EntryClass::Person.to_value());
3753 let e = e.into_sealed_committed();
3754
3755 assert!(Entry::idx_name2uuid_diff(None, Some(&e)) == (Some(Set::new()), None));
3756 }
3757
3758 {
3759 let mut e: Entry<EntryInit, EntryNew> = Entry::new();
3760 e.add_ava(Attribute::Class, EntryClass::Person.to_value());
3761 e.add_ava(Attribute::GidNumber, Value::new_uint32(1300));
3762 e.add_ava(Attribute::Name, Value::new_iname("testperson"));
3763 e.add_ava(
3764 Attribute::Spn,
3765 Value::new_spn_str("testperson", "example.com"),
3766 );
3767 e.add_ava(
3768 Attribute::Uuid,
3769 Value::Uuid(uuid!("9fec0398-c46c-4df4-9df5-b0016f7d563f")),
3770 );
3771 let e = e.into_sealed_committed();
3772
3773 assert!(
3775 Entry::idx_name2uuid_diff(None, Some(&e))
3776 == (
3777 Some(btreeset![
3778 "1300".to_string(),
3779 "testperson".to_string(),
3780 "testperson@example.com".to_string()
3781 ]),
3782 None
3783 )
3784 );
3785 assert!(
3788 Entry::idx_name2uuid_diff(Some(&e), None)
3789 == (
3790 None,
3791 Some(btreeset![
3792 "1300".to_string(),
3793 "testperson".to_string(),
3794 "testperson@example.com".to_string()
3795 ])
3796 )
3797 );
3798
3799 assert!(
3801 Entry::idx_name2uuid_diff(Some(&e), Some(&e))
3802 == (Some(Set::new()), Some(Set::new()))
3803 );
3804 }
3805 {
3808 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3809 e1.add_ava(Attribute::Class, EntryClass::Person.to_value());
3810 e1.add_ava(
3811 Attribute::Spn,
3812 Value::new_spn_str("testperson", "example.com"),
3813 );
3814 let e1 = e1.into_sealed_committed();
3815
3816 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3817 e2.add_ava(Attribute::Class, EntryClass::Person.to_value());
3818 e2.add_ava(Attribute::Name, Value::new_iname("testperson"));
3819 e2.add_ava(
3820 Attribute::Spn,
3821 Value::new_spn_str("testperson", "example.com"),
3822 );
3823 let e2 = e2.into_sealed_committed();
3824
3825 assert!(
3827 Entry::idx_name2uuid_diff(Some(&e1), Some(&e2))
3828 == (Some(btreeset!["testperson".to_string()]), Some(Set::new()))
3829 );
3830
3831 assert!(
3833 Entry::idx_name2uuid_diff(Some(&e2), Some(&e1))
3834 == (Some(Set::new()), Some(btreeset!["testperson".to_string()]))
3835 );
3836 }
3837
3838 {
3840 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3841 e1.add_ava(Attribute::Class, EntryClass::Person.to_value());
3842 e1.add_ava(
3843 Attribute::Spn,
3844 Value::new_spn_str("testperson", "example.com"),
3845 );
3846 let e1 = e1.into_sealed_committed();
3847
3848 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3849 e2.add_ava(Attribute::Class, EntryClass::Person.to_value());
3850 e2.add_ava(
3851 Attribute::Spn,
3852 Value::new_spn_str("renameperson", "example.com"),
3853 );
3854 let e2 = e2.into_sealed_committed();
3855
3856 assert!(
3857 Entry::idx_name2uuid_diff(Some(&e1), Some(&e2))
3858 == (
3859 Some(btreeset!["renameperson@example.com".to_string()]),
3860 Some(btreeset!["testperson@example.com".to_string()])
3861 )
3862 );
3863 }
3864 }
3865
3866 #[test]
3867 fn test_entry_idx_uuid2spn_diff() {
3868 assert!(Entry::idx_uuid2spn_diff(None, None).is_none());
3869
3870 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3871 e1.add_ava(
3872 Attribute::Spn,
3873 Value::new_spn_str("testperson", "example.com"),
3874 );
3875 let e1 = e1.into_sealed_committed();
3876
3877 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3878 e2.add_ava(
3879 Attribute::Spn,
3880 Value::new_spn_str("renameperson", "example.com"),
3881 );
3882 let e2 = e2.into_sealed_committed();
3883
3884 assert!(
3885 Entry::idx_uuid2spn_diff(None, Some(&e1))
3886 == Some(Ok(Value::new_spn_str("testperson", "example.com")))
3887 );
3888 assert!(Entry::idx_uuid2spn_diff(Some(&e1), None) == Some(Err(())));
3889 assert!(Entry::idx_uuid2spn_diff(Some(&e1), Some(&e1)).is_none());
3890 assert!(
3891 Entry::idx_uuid2spn_diff(Some(&e1), Some(&e2))
3892 == Some(Ok(Value::new_spn_str("renameperson", "example.com")))
3893 );
3894 }
3895
3896 #[test]
3897 fn test_entry_idx_uuid2rdn_diff() {
3898 assert!(Entry::idx_uuid2rdn_diff(None, None).is_none());
3899
3900 let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
3901 e1.add_ava(
3902 Attribute::Spn,
3903 Value::new_spn_str("testperson", "example.com"),
3904 );
3905 let e1 = e1.into_sealed_committed();
3906
3907 let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
3908 e2.add_ava(
3909 Attribute::Spn,
3910 Value::new_spn_str("renameperson", "example.com"),
3911 );
3912 let e2 = e2.into_sealed_committed();
3913
3914 assert!(
3915 Entry::idx_uuid2rdn_diff(None, Some(&e1))
3916 == Some(Ok("spn=testperson@example.com".to_string()))
3917 );
3918 assert!(Entry::idx_uuid2rdn_diff(Some(&e1), None) == Some(Err(())));
3919 assert!(Entry::idx_uuid2rdn_diff(Some(&e1), Some(&e1)).is_none());
3920 assert!(
3921 Entry::idx_uuid2rdn_diff(Some(&e1), Some(&e2))
3922 == Some(Ok("spn=renameperson@example.com".to_string()))
3923 );
3924 }
3925}