1use crate::be::IdxKey;
20use crate::prelude::*;
21use crate::valueset::ValueSet;
22use concread::cowcell::*;
23use hashbrown::{HashMap, HashSet};
24use std::collections::BTreeSet;
25use tracing::trace;
26use uuid::Uuid;
27
28pub struct Schema {
45 classes: CowCell<HashMap<AttrString, SchemaClass>>,
46 attributes: CowCell<HashMap<Attribute, SchemaAttribute>>,
47 unique_cache: CowCell<Vec<Attribute>>,
48 ref_cache: CowCell<HashMap<Attribute, SchemaAttribute>>,
49}
50
51pub struct SchemaWriteTransaction<'a> {
55 classes: CowCellWriteTxn<'a, HashMap<AttrString, SchemaClass>>,
56 attributes: CowCellWriteTxn<'a, HashMap<Attribute, SchemaAttribute>>,
57
58 unique_cache: CowCellWriteTxn<'a, Vec<Attribute>>,
59 ref_cache: CowCellWriteTxn<'a, HashMap<Attribute, SchemaAttribute>>,
60}
61
62pub struct SchemaReadTransaction {
64 classes: CowCellReadTxn<HashMap<AttrString, SchemaClass>>,
65 attributes: CowCellReadTxn<HashMap<Attribute, SchemaAttribute>>,
66
67 unique_cache: CowCellReadTxn<Vec<Attribute>>,
68 ref_cache: CowCellReadTxn<HashMap<Attribute, SchemaAttribute>>,
69}
70
71#[derive(Debug, Clone, Copy, Default)]
72pub enum Replicated {
73 #[default]
74 True,
75 False,
76}
77
78impl From<Replicated> for bool {
79 fn from(value: Replicated) -> bool {
80 match value {
81 Replicated::True => true,
82 Replicated::False => false,
83 }
84 }
85}
86
87impl From<bool> for Replicated {
88 fn from(value: bool) -> Self {
89 match value {
90 true => Replicated::True,
91 false => Replicated::False,
92 }
93 }
94}
95
96#[derive(Debug, Clone, Default)]
104pub struct SchemaAttribute {
105 pub name: Attribute,
106 pub uuid: Uuid,
107 pub description: String,
108 pub multivalue: bool,
110 pub unique: bool,
112 pub phantom: bool,
116 pub sync_allowed: bool,
119
120 pub replicated: Replicated,
122 pub indexed: bool,
124 pub syntax: SyntaxType,
126}
127
128impl SchemaAttribute {
129 pub fn try_from(value: &Entry<EntrySealed, EntryCommitted>) -> Result<Self, OperationError> {
130 let uuid = value.get_uuid();
134
135 if !value.attribute_equality(Attribute::Class, &EntryClass::AttributeType.into()) {
137 admin_error!(
138 "class {} not present - {:?}",
139 EntryClass::AttributeType,
140 uuid
141 );
142 return Err(OperationError::InvalidSchemaState(format!(
143 "missing {}",
144 EntryClass::AttributeType
145 )));
146 }
147
148 let name = value
150 .get_ava_single_iutf8(Attribute::AttributeName)
151 .map(|s| s.into())
152 .ok_or_else(|| {
153 admin_error!("missing {} - {:?}", Attribute::AttributeName, uuid);
154 OperationError::InvalidSchemaState("missing attributename".to_string())
155 })?;
156 let description = value
158 .get_ava_single_utf8(Attribute::Description)
159 .map(|s| s.to_string())
160 .ok_or_else(|| {
161 admin_error!("missing {} - {}", Attribute::Description, name);
162 OperationError::InvalidSchemaState("missing description".to_string())
163 })?;
164
165 let multivalue = value
167 .get_ava_single_bool(Attribute::MultiValue)
168 .ok_or_else(|| {
169 admin_error!("missing {} - {}", Attribute::MultiValue, name);
170 OperationError::InvalidSchemaState("missing multivalue".to_string())
171 })?;
172
173 let unique = value
174 .get_ava_single_bool(Attribute::Unique)
175 .ok_or_else(|| {
176 admin_error!("missing {} - {}", Attribute::Unique, name);
177 OperationError::InvalidSchemaState("missing unique".to_string())
178 })?;
179
180 let phantom = value
181 .get_ava_single_bool(Attribute::Phantom)
182 .unwrap_or_default();
183
184 let sync_allowed = value
185 .get_ava_single_bool(Attribute::SyncAllowed)
186 .unwrap_or_default();
187
188 let replicated = value
191 .get_ava_single_bool(Attribute::Replicated)
192 .map(Replicated::from)
193 .unwrap_or_default();
194
195 let indexed = value
196 .get_ava_single_bool(Attribute::Indexed)
197 .unwrap_or_default();
198
199 let syntax = value
201 .get_ava_single_syntax(Attribute::Syntax)
202 .ok_or_else(|| {
203 admin_error!("missing {} - {}", Attribute::Syntax, name);
204 OperationError::InvalidSchemaState(format!("missing {}", Attribute::Syntax))
205 })?;
206
207 trace!(?name, ?indexed);
208
209 Ok(SchemaAttribute {
210 name,
211 uuid,
212 description,
213 multivalue,
214 unique,
215 phantom,
216 sync_allowed,
217 replicated,
218 indexed,
219 syntax,
220 })
221 }
222
223 pub fn validate_partialvalue(
227 &self,
228 a: &Attribute,
229 v: &PartialValue,
230 ) -> Result<(), SchemaError> {
231 let r = match self.syntax {
232 SyntaxType::Boolean => matches!(v, PartialValue::Bool(_)),
233 SyntaxType::SyntaxId => matches!(v, PartialValue::Syntax(_)),
234 SyntaxType::IndexId => matches!(v, PartialValue::Index(_)),
235 SyntaxType::Uuid => matches!(v, PartialValue::Uuid(_)),
236 SyntaxType::ReferenceUuid => matches!(v, PartialValue::Refer(_)),
237 SyntaxType::Utf8StringInsensitive => matches!(v, PartialValue::Iutf8(_)),
238 SyntaxType::Utf8StringIname => matches!(v, PartialValue::Iname(_)),
239 SyntaxType::Utf8String => matches!(v, PartialValue::Utf8(_)),
240 SyntaxType::JsonFilter => matches!(v, PartialValue::JsonFilt(_)),
241 SyntaxType::Credential => matches!(v, PartialValue::Cred(_)),
242 SyntaxType::SecretUtf8String => matches!(v, PartialValue::SecretValue),
243 SyntaxType::SshKey => matches!(v, PartialValue::SshKey(_)),
244 SyntaxType::SecurityPrincipalName => matches!(v, PartialValue::Spn(_, _)),
245 SyntaxType::Uint32 => matches!(v, PartialValue::Uint32(_)),
246 SyntaxType::Cid => matches!(v, PartialValue::Cid(_)),
247 SyntaxType::NsUniqueId => matches!(v, PartialValue::Nsuniqueid(_)),
248 SyntaxType::DateTime => matches!(v, PartialValue::DateTime(_)),
249 SyntaxType::EmailAddress => matches!(v, PartialValue::EmailAddress(_)),
250 SyntaxType::Url => matches!(v, PartialValue::Url(_)),
251 SyntaxType::OauthScope => matches!(v, PartialValue::OauthScope(_)),
252 SyntaxType::OauthScopeMap => matches!(v, PartialValue::Refer(_)),
253 SyntaxType::OauthClaimMap => {
254 matches!(v, PartialValue::Iutf8(_))
255 || matches!(v, PartialValue::Refer(_))
256 || matches!(v, PartialValue::OauthClaimValue(_, _, _))
257 || matches!(v, PartialValue::OauthClaim(_, _))
258 }
259 SyntaxType::PrivateBinary => matches!(v, PartialValue::PrivateBinary),
260 SyntaxType::IntentToken => matches!(v, PartialValue::IntentToken(_)),
261 SyntaxType::Passkey => matches!(v, PartialValue::Passkey(_)),
262 SyntaxType::AttestedPasskey => matches!(v, PartialValue::AttestedPasskey(_)),
263 SyntaxType::Session => matches!(v, PartialValue::Refer(_)),
265 SyntaxType::ApiToken => matches!(v, PartialValue::Refer(_)),
266 SyntaxType::Oauth2Session => matches!(v, PartialValue::Refer(_)),
267 SyntaxType::JwsKeyEs256 => matches!(v, PartialValue::Iutf8(_)),
269 SyntaxType::JwsKeyRs256 => matches!(v, PartialValue::Iutf8(_)),
270 SyntaxType::UiHint => matches!(v, PartialValue::UiHint(_)),
271 SyntaxType::EcKeyPrivate => matches!(v, PartialValue::SecretValue),
272 SyntaxType::TotpSecret => matches!(v, PartialValue::Utf8(_)),
274 SyntaxType::AuditLogString => matches!(v, PartialValue::Utf8(_)),
275 SyntaxType::Image => matches!(v, PartialValue::Utf8(_)),
276 SyntaxType::CredentialType => matches!(v, PartialValue::CredentialType(_)),
277
278 SyntaxType::HexString | SyntaxType::Certificate | SyntaxType::KeyInternal => {
279 matches!(v, PartialValue::HexString(_))
280 }
281
282 SyntaxType::WebauthnAttestationCaList => false,
283 SyntaxType::ApplicationPassword => {
284 matches!(v, PartialValue::Uuid(_)) || matches!(v, PartialValue::Refer(_))
285 }
286 SyntaxType::Json | SyntaxType::Message => false,
289 };
290 if r {
291 Ok(())
292 } else {
293 error!(
294 ?a,
295 ?self,
296 ?v,
297 "validate_partialvalue InvalidAttributeSyntax"
298 );
299 Err(SchemaError::InvalidAttributeSyntax(a.to_string()))
300 }
301 }
302
303 pub fn validate_value(&self, a: &Attribute, v: &Value) -> Result<(), SchemaError> {
304 let r = v.validate()
305 && match self.syntax {
306 SyntaxType::Boolean => matches!(v, Value::Bool(_)),
307 SyntaxType::SyntaxId => matches!(v, Value::Syntax(_)),
308 SyntaxType::IndexId => matches!(v, Value::Index(_)),
309 SyntaxType::Uuid => matches!(v, Value::Uuid(_)),
310 SyntaxType::ReferenceUuid => matches!(v, Value::Refer(_)),
311 SyntaxType::Utf8StringInsensitive => matches!(v, Value::Iutf8(_)),
312 SyntaxType::Utf8StringIname => matches!(v, Value::Iname(_)),
313 SyntaxType::Utf8String => matches!(v, Value::Utf8(_)),
314 SyntaxType::JsonFilter => matches!(v, Value::JsonFilt(_)),
315 SyntaxType::Credential => matches!(v, Value::Cred(_, _)),
316 SyntaxType::SecretUtf8String => matches!(v, Value::SecretValue(_)),
317 SyntaxType::SshKey => matches!(v, Value::SshKey(_, _)),
318 SyntaxType::SecurityPrincipalName => matches!(v, Value::Spn(_, _)),
319 SyntaxType::Uint32 => matches!(v, Value::Uint32(_)),
320 SyntaxType::Cid => matches!(v, Value::Cid(_)),
321 SyntaxType::NsUniqueId => matches!(v, Value::Nsuniqueid(_)),
322 SyntaxType::DateTime => matches!(v, Value::DateTime(_)),
323 SyntaxType::EmailAddress => matches!(v, Value::EmailAddress(_, _)),
324 SyntaxType::Url => matches!(v, Value::Url(_)),
325 SyntaxType::OauthScope => matches!(v, Value::OauthScope(_)),
326 SyntaxType::OauthScopeMap => matches!(v, Value::OauthScopeMap(_, _)),
327 SyntaxType::OauthClaimMap => {
328 matches!(v, Value::OauthClaimValue(_, _, _))
329 || matches!(v, Value::OauthClaimMap(_, _))
330 }
331 SyntaxType::PrivateBinary => matches!(v, Value::PrivateBinary(_)),
332 SyntaxType::IntentToken => matches!(v, Value::IntentToken(_, _)),
333 SyntaxType::Passkey => matches!(v, Value::Passkey(_, _, _)),
334 SyntaxType::AttestedPasskey => matches!(v, Value::AttestedPasskey(_, _, _)),
335 SyntaxType::Session => matches!(v, Value::Session(_, _)),
336 SyntaxType::ApiToken => matches!(v, Value::ApiToken(_, _)),
337 SyntaxType::Oauth2Session => matches!(v, Value::Oauth2Session(_, _)),
338 SyntaxType::JwsKeyEs256 => matches!(v, Value::JwsKeyEs256(_)),
339 SyntaxType::JwsKeyRs256 => matches!(v, Value::JwsKeyRs256(_)),
340 SyntaxType::UiHint => matches!(v, Value::UiHint(_)),
341 SyntaxType::TotpSecret => matches!(v, Value::TotpSecret(_, _)),
342 SyntaxType::AuditLogString => matches!(v, Value::Utf8(_)),
343 SyntaxType::EcKeyPrivate => matches!(v, Value::EcKeyPrivate(_)),
344 SyntaxType::Image => matches!(v, Value::Image(_)),
345 SyntaxType::CredentialType => matches!(v, Value::CredentialType(_)),
346 SyntaxType::WebauthnAttestationCaList => {
347 matches!(v, Value::WebauthnAttestationCaList(_))
348 }
349 SyntaxType::KeyInternal => matches!(v, Value::KeyInternal { .. }),
350 SyntaxType::HexString => matches!(v, Value::HexString(_)),
351 SyntaxType::Certificate => matches!(v, Value::Certificate(_)),
352 SyntaxType::ApplicationPassword => matches!(v, Value::ApplicationPassword(..)),
353 SyntaxType::Json => matches!(v, Value::Json(_)),
354 SyntaxType::Message => false,
355 };
356 if r {
357 Ok(())
358 } else {
359 error!(
360 ?a,
361 ?self,
362 ?v,
363 "validate_value failure - InvalidAttributeSyntax"
364 );
365 Err(SchemaError::InvalidAttributeSyntax(a.to_string()))
366 }
367 }
368
369 pub fn validate_ava(&self, a: &Attribute, ava: &ValueSet) -> Result<(), SchemaError> {
370 trace!("Checking for valid {:?} -> {:?}", self.name, ava);
371 if !self.multivalue && ava.len() > 1 {
373 admin_error!("Ava len > 1 on single value attribute!");
375 return Err(SchemaError::InvalidAttributeSyntax(a.to_string()));
376 };
377 let valid = self.syntax == ava.syntax();
379 if valid && ava.validate(self) {
380 Ok(())
381 } else {
382 error!(
383 ?a,
384 "validate_ava - InvalidAttributeSyntax for {:?}", self.syntax
385 );
386 Err(SchemaError::InvalidAttributeSyntax(a.to_string()))
387 }
388 }
389}
390
391#[derive(Debug, Clone, Default)]
409pub struct SchemaClass {
410 pub name: AttrString,
411 pub uuid: Uuid,
412 pub description: String,
413 pub sync_allowed: bool,
414 pub systemmay: Vec<Attribute>,
416 pub may: Vec<Attribute>,
417 pub systemmust: Vec<Attribute>,
418 pub must: Vec<Attribute>,
419 pub systemsupplements: Vec<AttrString>,
424 pub supplements: Vec<AttrString>,
425 pub systemexcludes: Vec<AttrString>,
427 pub excludes: Vec<AttrString>,
428}
429
430impl SchemaClass {
431 pub fn try_from(value: &Entry<EntrySealed, EntryCommitted>) -> Result<Self, OperationError> {
432 let uuid = value.get_uuid();
434 if !value.attribute_equality(Attribute::Class, &EntryClass::ClassType.into()) {
436 error!("class classtype not present - {:?}", uuid);
437 return Err(OperationError::InvalidSchemaState(
438 "missing classtype".to_string(),
439 ));
440 }
441
442 let name = value
444 .get_ava_single_iutf8(Attribute::ClassName)
445 .map(AttrString::from)
446 .ok_or_else(|| {
447 error!("missing {} - {:?}", Attribute::ClassName, uuid);
448 OperationError::InvalidSchemaState(format!("missing {}", Attribute::ClassName))
449 })?;
450
451 let description = value
453 .get_ava_single_utf8(Attribute::Description)
454 .map(String::from)
455 .ok_or_else(|| {
456 error!("missing {} - {}", Attribute::Description, name);
457 OperationError::InvalidSchemaState(format!("missing {}", Attribute::Description))
458 })?;
459
460 let sync_allowed = value
461 .get_ava_single_bool(Attribute::SyncAllowed)
462 .unwrap_or(false);
463
464 let systemmay = value
466 .get_ava_iter_iutf8(Attribute::SystemMay)
467 .into_iter()
468 .flat_map(|iter| iter.map(Attribute::from))
469 .collect();
470 let systemmust = value
471 .get_ava_iter_iutf8(Attribute::SystemMust)
472 .into_iter()
473 .flat_map(|iter| iter.map(Attribute::from))
474 .collect();
475 let may = value
476 .get_ava_iter_iutf8(Attribute::May)
477 .into_iter()
478 .flat_map(|iter| iter.map(Attribute::from))
479 .collect();
480 let must = value
481 .get_ava_iter_iutf8(Attribute::Must)
482 .into_iter()
483 .flat_map(|iter| iter.map(Attribute::from))
484 .collect();
485
486 let systemsupplements = value
487 .get_ava_iter_iutf8(Attribute::SystemSupplements)
488 .map(|i| i.map(|v| v.into()).collect())
489 .unwrap_or_default();
490 let supplements = value
491 .get_ava_iter_iutf8(Attribute::Supplements)
492 .map(|i| i.map(|v| v.into()).collect())
493 .unwrap_or_default();
494 let systemexcludes = value
495 .get_ava_iter_iutf8(Attribute::SystemExcludes)
496 .map(|i| i.map(|v| v.into()).collect())
497 .unwrap_or_default();
498 let excludes = value
499 .get_ava_iter_iutf8(Attribute::Excludes)
500 .map(|i| i.map(|v| v.into()).collect())
501 .unwrap_or_default();
502
503 Ok(SchemaClass {
504 name,
505 uuid,
506 description,
507 sync_allowed,
508 systemmay,
509 may,
510 systemmust,
511 must,
512 systemsupplements,
513 supplements,
514 systemexcludes,
515 excludes,
516 })
517 }
518
519 pub fn may_iter(&self) -> impl Iterator<Item = &Attribute> {
522 self.systemmay
523 .iter()
524 .chain(self.may.iter())
525 .chain(self.systemmust.iter())
526 .chain(self.must.iter())
527 }
528}
529
530pub trait SchemaTransaction {
531 fn get_classes(&self) -> &HashMap<AttrString, SchemaClass>;
532 fn get_attributes(&self) -> &HashMap<Attribute, SchemaAttribute>;
533
534 fn get_attributes_unique(&self) -> &Vec<Attribute>;
535 fn get_reference_types(&self) -> &HashMap<Attribute, SchemaAttribute>;
536
537 fn validate(&self) -> Vec<Result<(), ConsistencyError>> {
538 let mut res = Vec::with_capacity(0);
539
540 let class_snapshot = self.get_classes();
541 let attribute_snapshot = self.get_attributes();
542
543 let mut unique_uuid_set = HashSet::new();
548 class_snapshot
549 .values()
550 .map(|class| &class.uuid)
551 .chain(attribute_snapshot.values().map(|attr| &attr.uuid))
552 .for_each(|uuid| {
553 if !unique_uuid_set.insert(uuid) {
555 res.push(Err(ConsistencyError::SchemaUuidNotUnique(*uuid)))
556 }
557 });
558
559 class_snapshot.values().for_each(|class| {
560 class
562 .systemmay
563 .iter()
564 .chain(class.may.iter())
565 .chain(class.systemmust.iter())
566 .chain(class.must.iter())
567 .for_each(|a| {
568 match attribute_snapshot.get(a) {
569 Some(attr) => {
570 if attr.phantom {
572 res.push(Err(ConsistencyError::SchemaClassPhantomAttribute(
573 class.name.to_string(),
574 a.to_string(),
575 )))
576 }
577 }
578 None => {
579 res.push(Err(ConsistencyError::SchemaClassMissingAttribute(
581 class.name.to_string(),
582 a.to_string(),
583 )))
584 }
585 }
586 })
587 }); res
589 }
590
591 fn is_replicated(&self, attr: &Attribute) -> bool {
592 match self.get_attributes().get(attr) {
593 Some(a_schema) => {
594 a_schema.replicated.into() && !a_schema.phantom
597 }
598 None => {
599 warn!(
600 "Attribute {} was not found in schema during replication request",
601 attr
602 );
603 false
604 }
605 }
606 }
607
608 fn is_multivalue(&self, attr: &Attribute) -> Result<bool, SchemaError> {
609 match self.get_attributes().get(attr) {
610 Some(a_schema) => Ok(a_schema.multivalue),
611 None => {
612 Err(SchemaError::InvalidAttribute(attr.to_string()))
614 }
615 }
616 }
617
618 fn normalise_attr_if_exists(&self, an: &str) -> Option<Attribute> {
619 let attr = Attribute::from(an);
620 if self.get_attributes().contains_key(&attr) {
621 Some(attr)
622 } else {
623 None
624 }
625 }
626
627 fn query_attrs_difference(
628 &self,
629 prev_class: &BTreeSet<&str>,
630 new_iutf8: &BTreeSet<&str>,
631 ) -> Result<(BTreeSet<&str>, BTreeSet<&str>), SchemaError> {
632 let schema_classes = self.get_classes();
633
634 let mut invalid_classes = Vec::with_capacity(0);
635
636 let prev_attrs: BTreeSet<&str> = prev_class
637 .iter()
638 .filter_map(|cls| match schema_classes.get(*cls) {
639 Some(x) => Some(x.may_iter()),
640 None => {
641 admin_debug!("invalid class: {:?}", cls);
642 invalid_classes.push(cls.to_string());
643 None
644 }
645 })
646 .flatten()
648 .map(|s| s.as_str())
649 .collect();
650
651 if !invalid_classes.is_empty() {
652 return Err(SchemaError::InvalidClass(invalid_classes));
653 };
654
655 let new_attrs: BTreeSet<&str> = new_iutf8
656 .iter()
657 .filter_map(|cls| match schema_classes.get(*cls) {
658 Some(x) => Some(x.may_iter()),
659 None => {
660 admin_debug!("invalid class: {:?}", cls);
661 invalid_classes.push(cls.to_string());
662 None
663 }
664 })
665 .flatten()
667 .map(|s| s.as_str())
668 .collect();
669
670 if !invalid_classes.is_empty() {
671 return Err(SchemaError::InvalidClass(invalid_classes));
672 };
673
674 let removed = prev_attrs.difference(&new_attrs).copied().collect();
675 let added = new_attrs.difference(&prev_attrs).copied().collect();
676
677 Ok((added, removed))
678 }
679}
680
681impl SchemaWriteTransaction<'_> {
682 pub fn commit(self) -> Result<(), OperationError> {
688 let SchemaWriteTransaction {
689 classes,
690 attributes,
691 unique_cache,
692 ref_cache,
693 } = self;
694
695 unique_cache.commit();
696 ref_cache.commit();
697 classes.commit();
698 attributes.commit();
699 Ok(())
700 }
701
702 pub fn update_attributes(
703 &mut self,
704 attributetypes: Vec<SchemaAttribute>,
705 ) -> Result<(), OperationError> {
706 self.attributes.clear();
708
709 self.unique_cache.clear();
710 self.ref_cache.clear();
711 attributetypes.into_iter().for_each(|a| {
715 if a.syntax == SyntaxType::ReferenceUuid ||
717 a.syntax == SyntaxType::OauthScopeMap ||
718 a.syntax == SyntaxType::OauthClaimMap ||
719 a.syntax == SyntaxType::Oauth2Session ||
721 a.syntax == SyntaxType::ApplicationPassword
723 {
726 self.ref_cache.insert(a.name.clone(), a.clone());
727 }
728 if a.unique {
729 self.unique_cache.push(a.name.clone());
730 }
731 self.attributes.insert(a.name.clone(), a);
733 });
734
735 Ok(())
736 }
737
738 pub fn update_classes(&mut self, classtypes: Vec<SchemaClass>) -> Result<(), OperationError> {
739 self.classes.clear();
741 classtypes.into_iter().for_each(|a| {
745 self.classes.insert(a.name.clone(), a);
746 });
747 Ok(())
748 }
749
750 pub fn to_entries(&self) -> Vec<Entry<EntryInit, EntryNew>> {
751 let r: Vec<_> = self
752 .attributes
753 .values()
754 .map(Entry::<EntryInit, EntryNew>::from)
755 .chain(
756 self.classes
757 .values()
758 .map(Entry::<EntryInit, EntryNew>::from),
759 )
760 .collect();
761 r
762 }
763
764 pub fn reload_idxmeta(&self) -> Vec<IdxKey> {
765 self.get_attributes()
766 .values()
767 .flat_map(|a| {
768 if a.indexed || a.unique {
770 a.syntax.index_types()
771 } else {
772 &[]
773 }
774 .iter()
775 .map(move |itype: &IndexType| IdxKey {
776 attr: a.name.clone(),
777 itype: *itype,
778 })
779 })
780 .collect()
781 }
782
783 #[instrument(level = "debug", name = "schema::generate_in_memory", skip_all)]
792 pub fn generate_in_memory(&mut self) -> Result<(), OperationError> {
793 self.classes.clear();
794 self.attributes.clear();
795 self.attributes.insert(
798 Attribute::Class,
799 SchemaAttribute {
800 name: Attribute::Class,
801 uuid: UUID_SCHEMA_ATTR_CLASS,
802 description: String::from("The set of classes defining an object"),
803 multivalue: true,
804 unique: false,
805 phantom: false,
806 sync_allowed: false,
807 replicated: Replicated::True,
808 indexed: true,
809 syntax: SyntaxType::Utf8StringInsensitive,
810 },
811 );
812 self.attributes.insert(
813 Attribute::Uuid,
814 SchemaAttribute {
815 name: Attribute::Uuid,
816 uuid: UUID_SCHEMA_ATTR_UUID,
817 description: String::from("The universal unique id of the object"),
818 multivalue: false,
819 unique: false,
822 phantom: false,
823 sync_allowed: false,
824 replicated: Replicated::True,
825 indexed: true,
826 syntax: SyntaxType::Uuid,
827 },
828 );
829 self.attributes.insert(
830 Attribute::SourceUuid,
831 SchemaAttribute {
832 name: Attribute::SourceUuid,
833 uuid: UUID_SCHEMA_ATTR_SOURCE_UUID,
834 description: String::from(
835 "The universal unique id of the source object(s) which conflicted with this entry",
836 ),
837 multivalue: true,
838 unique: false,
841 phantom: false,
842 sync_allowed: false,
843 replicated: Replicated::True,
844 indexed: true,
845 syntax: SyntaxType::Uuid,
846 },
847 );
848 self.attributes.insert(
849 Attribute::CreatedAtCid,
850 SchemaAttribute {
851 name: Attribute::CreatedAtCid,
852 uuid: UUID_SCHEMA_ATTR_CREATED_AT_CID,
853 description: String::from("The cid when this entry was created"),
854 multivalue: false,
855 unique: false,
858 phantom: false,
859 sync_allowed: false,
860 replicated: Replicated::False,
861 indexed: false,
862 syntax: SyntaxType::Cid,
863 },
864 );
865 self.attributes.insert(
866 Attribute::LastModifiedCid,
867 SchemaAttribute {
868 name: Attribute::LastModifiedCid,
869 uuid: UUID_SCHEMA_ATTR_LAST_MOD_CID,
870 description: String::from("The cid of the last change to this object"),
871 multivalue: false,
872 unique: false,
875 phantom: false,
876 sync_allowed: false,
877 replicated: Replicated::False,
878 indexed: false,
879 syntax: SyntaxType::Cid,
880 },
881 );
882 self.attributes.insert(
883 Attribute::Name,
884 SchemaAttribute {
885 name: Attribute::Name,
886 uuid: UUID_SCHEMA_ATTR_NAME,
887 description: String::from("The shortform name of an object"),
888 multivalue: false,
889 unique: true,
890 phantom: false,
891 sync_allowed: true,
892 replicated: Replicated::True,
893 indexed: true,
894 syntax: SyntaxType::Utf8StringIname,
895 },
896 );
897 self.attributes.insert(
898 Attribute::Spn,
899 SchemaAttribute {
900 name: Attribute::Spn,
901 uuid: UUID_SCHEMA_ATTR_SPN,
902 description: String::from(
903 "The Security Principal Name of an object, unique across all domain trusts",
904 ),
905 multivalue: false,
906 unique: true,
907 phantom: false,
908 sync_allowed: false,
909 replicated: Replicated::True,
910 indexed: true,
911 syntax: SyntaxType::SecurityPrincipalName,
912 },
913 );
914 self.attributes.insert(
915 Attribute::AttributeName,
916 SchemaAttribute {
917 name: Attribute::AttributeName,
918 uuid: UUID_SCHEMA_ATTR_ATTRIBUTENAME,
919 description: String::from("The name of a schema attribute"),
920 multivalue: false,
921 unique: true,
922 phantom: false,
923 sync_allowed: false,
924 replicated: Replicated::True,
925 indexed: true,
926 syntax: SyntaxType::Utf8StringInsensitive,
927 },
928 );
929 self.attributes.insert(
930 Attribute::ClassName,
931 SchemaAttribute {
932 name: Attribute::ClassName,
933 uuid: UUID_SCHEMA_ATTR_CLASSNAME,
934 description: String::from("The name of a schema class"),
935 multivalue: false,
936 unique: true,
937 phantom: false,
938 sync_allowed: false,
939 replicated: Replicated::True,
940 indexed: true,
941 syntax: SyntaxType::Utf8StringInsensitive,
942 },
943 );
944 self.attributes.insert(
945 Attribute::Description,
946 SchemaAttribute {
947 name: Attribute::Description,
948 uuid: UUID_SCHEMA_ATTR_DESCRIPTION,
949 description: String::from("A description of an attribute, object or class"),
950 multivalue: false,
951 unique: false,
952 phantom: false,
953 sync_allowed: true,
954 replicated: Replicated::True,
955 indexed: false,
956 syntax: SyntaxType::Utf8String,
957 },
958 );
959 self.attributes.insert(Attribute::MultiValue, SchemaAttribute {
960 name: Attribute::MultiValue,
961 uuid: UUID_SCHEMA_ATTR_MULTIVALUE,
962 description: String::from("If true, this attribute is able to store multiple values rather than just a single value."),
963 multivalue: false,
964 unique: false,
965 phantom: false,
966 sync_allowed: false,
967 replicated: Replicated::True,
968 indexed: false,
969 syntax: SyntaxType::Boolean,
970 });
971 self.attributes.insert(Attribute::Phantom, SchemaAttribute {
972 name: Attribute::Phantom,
973 uuid: UUID_SCHEMA_ATTR_PHANTOM,
974 description: String::from("If true, this attribute must NOT be present in any may/must sets of a class as. This represents generated attributes."),
975 multivalue: false,
976 unique: false,
977 phantom: false,
978 sync_allowed: false,
979 replicated: Replicated::True,
980 indexed: false,
981 syntax: SyntaxType::Boolean,
982 });
983 self.attributes.insert(Attribute::SyncAllowed, SchemaAttribute {
984 name: Attribute::SyncAllowed,
985 uuid: UUID_SCHEMA_ATTR_SYNC_ALLOWED,
986 description: String::from("If true, this attribute or class can by synchronised by an external scim import"),
987 multivalue: false,
988 unique: false,
989 phantom: false,
990 sync_allowed: false,
991 replicated: Replicated::True,
992 indexed: false,
993 syntax: SyntaxType::Boolean,
994 });
995 self.attributes.insert(Attribute::Replicated, SchemaAttribute {
996 name: Attribute::Replicated,
997 uuid: UUID_SCHEMA_ATTR_REPLICATED,
998 description: String::from("If true, this attribute or class can by replicated between nodes in the topology"),
999 multivalue: false,
1000 unique: false,
1001 phantom: false,
1002 sync_allowed: false,
1003 replicated: Replicated::True,
1004 indexed: false,
1005 syntax: SyntaxType::Boolean,
1006 });
1007 self.attributes.insert(
1008 Attribute::Unique,
1009 SchemaAttribute {
1010 name: Attribute::Unique,
1011 uuid: UUID_SCHEMA_ATTR_UNIQUE,
1012 description: String::from(
1013 "If true, this attribute must store a unique value through out the database.",
1014 ),
1015 multivalue: false,
1016 unique: false,
1017 phantom: false,
1018 sync_allowed: false,
1019 replicated: Replicated::True,
1020 indexed: false,
1021 syntax: SyntaxType::Boolean,
1022 },
1023 );
1024 self.attributes.insert(
1025 Attribute::Index,
1026 SchemaAttribute {
1027 name: Attribute::Index,
1028 uuid: UUID_SCHEMA_ATTR_INDEX,
1029 description: String::from(
1030 "Describe the indexes to apply to instances of this attribute.",
1031 ),
1032 multivalue: true,
1033 unique: false,
1034 phantom: false,
1035 sync_allowed: false,
1036 replicated: Replicated::True,
1037 indexed: false,
1038 syntax: SyntaxType::IndexId,
1039 },
1040 );
1041 self.attributes.insert(
1042 Attribute::Indexed,
1043 SchemaAttribute {
1044 name: Attribute::Indexed,
1045 uuid: UUID_SCHEMA_ATTR_INDEXED,
1046 description: String::from(
1047 "A boolean stating if this attribute will be indexed according to its syntax rules."
1048 ),
1049 multivalue: false,
1050 unique: false,
1051 phantom: false,
1052 sync_allowed: false,
1053 replicated: Replicated::True,
1054 indexed: false,
1055 syntax: SyntaxType::Boolean,
1056 },
1057 );
1058 self.attributes.insert(
1059 Attribute::Syntax,
1060 SchemaAttribute {
1061 name: Attribute::Syntax,
1062 uuid: UUID_SCHEMA_ATTR_SYNTAX,
1063 description: String::from(
1064 "Describe the syntax of this attribute. This affects indexing and sorting.",
1065 ),
1066 multivalue: false,
1067 unique: false,
1068 phantom: false,
1069 sync_allowed: false,
1070 replicated: Replicated::True,
1071 indexed: false,
1072 syntax: SyntaxType::SyntaxId,
1073 },
1074 );
1075 self.attributes.insert(
1076 Attribute::SystemMay,
1077 SchemaAttribute {
1078 name: Attribute::SystemMay,
1079 uuid: UUID_SCHEMA_ATTR_SYSTEMMAY,
1080 description: String::from(
1081 "A list of system provided optional attributes this class can store.",
1082 ),
1083 multivalue: true,
1084 unique: false,
1085 phantom: false,
1086 sync_allowed: false,
1087 replicated: Replicated::True,
1088 indexed: false,
1089 syntax: SyntaxType::Utf8StringInsensitive,
1090 },
1091 );
1092 self.attributes.insert(
1093 Attribute::May,
1094 SchemaAttribute {
1095 name: Attribute::May,
1096 uuid: UUID_SCHEMA_ATTR_MAY,
1097 description: String::from(
1098 "A user modifiable list of optional attributes this class can store.",
1099 ),
1100 multivalue: true,
1101 unique: false,
1102 phantom: false,
1103 sync_allowed: false,
1104 replicated: Replicated::True,
1105 indexed: false,
1106 syntax: SyntaxType::Utf8StringInsensitive,
1107 },
1108 );
1109 self.attributes.insert(
1110 Attribute::SystemMust,
1111 SchemaAttribute {
1112 name: Attribute::SystemMust,
1113 uuid: UUID_SCHEMA_ATTR_SYSTEMMUST,
1114 description: String::from(
1115 "A list of system provided required attributes this class must store.",
1116 ),
1117 multivalue: true,
1118 unique: false,
1119 phantom: false,
1120 sync_allowed: false,
1121 replicated: Replicated::True,
1122 indexed: false,
1123 syntax: SyntaxType::Utf8StringInsensitive,
1124 },
1125 );
1126 self.attributes.insert(
1127 Attribute::Must,
1128 SchemaAttribute {
1129 name: Attribute::Must,
1130 uuid: UUID_SCHEMA_ATTR_MUST,
1131 description: String::from(
1132 "A user modifiable list of required attributes this class must store.",
1133 ),
1134 multivalue: true,
1135 unique: false,
1136 phantom: false,
1137 sync_allowed: false,
1138 replicated: Replicated::True,
1139 indexed: false,
1140 syntax: SyntaxType::Utf8StringInsensitive,
1141 },
1142 );
1143 self.attributes.insert(
1144 Attribute::SystemSupplements,
1145 SchemaAttribute {
1146 name: Attribute::SystemSupplements,
1147 uuid: UUID_SCHEMA_ATTR_SYSTEMSUPPLEMENTS,
1148 description: String::from(
1149 "A set of classes that this type supplements, where this class can't exist without their presence.",
1150 ),
1151 multivalue: true,
1152 unique: false,
1153 phantom: false,
1154 sync_allowed: false,
1155 replicated: Replicated::True,
1156 indexed: false,
1157 syntax: SyntaxType::Utf8StringInsensitive,
1158 },
1159 );
1160 self.attributes.insert(
1161 Attribute::Supplements,
1162 SchemaAttribute {
1163 name: Attribute::Supplements,
1164 uuid: UUID_SCHEMA_ATTR_SUPPLEMENTS,
1165 description: String::from(
1166 "A set of user modifiable classes, where this determines that at least one other type must supplement this type",
1167 ),
1168 multivalue: true,
1169 unique: false,
1170 phantom: false,
1171 sync_allowed: false,
1172 replicated: Replicated::True,
1173 indexed: false,
1174 syntax: SyntaxType::Utf8StringInsensitive,
1175 },
1176 );
1177 self.attributes.insert(
1178 Attribute::SystemExcludes,
1179 SchemaAttribute {
1180 name: Attribute::SystemExcludes,
1181 uuid: UUID_SCHEMA_ATTR_SYSTEMEXCLUDES,
1182 description: String::from(
1183 "A set of classes that are denied presence in connection to this class",
1184 ),
1185 multivalue: true,
1186 unique: false,
1187 phantom: false,
1188 sync_allowed: false,
1189 replicated: Replicated::True,
1190 indexed: false,
1191 syntax: SyntaxType::Utf8StringInsensitive,
1192 },
1193 );
1194 self.attributes.insert(
1195 Attribute::Excludes,
1196 SchemaAttribute {
1197 name: Attribute::Excludes,
1198 uuid: UUID_SCHEMA_ATTR_EXCLUDES,
1199 description: String::from(
1200 "A set of user modifiable classes that are denied presence in connection to this class",
1201 ),
1202 multivalue: true,
1203 unique: false,
1204 phantom: false,
1205 sync_allowed: false,
1206 replicated: Replicated::True,
1207 indexed: false,
1208 syntax: SyntaxType::Utf8StringInsensitive,
1209 },
1210 );
1211
1212 self.attributes.insert(
1215 Attribute::AcpEnable,
1216 SchemaAttribute {
1217 name: Attribute::AcpEnable,
1218 uuid: UUID_SCHEMA_ATTR_ACP_ENABLE,
1219 description: String::from("A flag to determine if this ACP is active for application. True is enabled, and enforced. False is checked but not enforced."),
1220 multivalue: false,
1221 unique: false,
1222 phantom: false,
1223 sync_allowed: false,
1224 replicated: Replicated::True,
1225 indexed: true,
1226 syntax: SyntaxType::Boolean,
1227 },
1228 );
1229
1230 self.attributes.insert(
1231 Attribute::AcpReceiver,
1232 SchemaAttribute {
1233 name: Attribute::AcpReceiver,
1234 uuid: UUID_SCHEMA_ATTR_ACP_RECEIVER,
1235 description: String::from(
1236 "Who the ACP applies to, constraining or allowing operations.",
1237 ),
1238 multivalue: false,
1239 unique: false,
1240 phantom: false,
1241 sync_allowed: false,
1242 replicated: Replicated::True,
1243 indexed: true,
1244 syntax: SyntaxType::JsonFilter,
1245 },
1246 );
1247 self.attributes.insert(
1248 Attribute::AcpReceiverGroup,
1249 SchemaAttribute {
1250 name: Attribute::AcpReceiverGroup,
1251 uuid: UUID_SCHEMA_ATTR_ACP_RECEIVER_GROUP,
1252 description: String::from(
1253 "The group that receives this access control to allow access",
1254 ),
1255 multivalue: true,
1256 unique: false,
1257 phantom: false,
1258 sync_allowed: false,
1259 replicated: Replicated::True,
1260 indexed: true,
1261 syntax: SyntaxType::ReferenceUuid,
1262 },
1263 );
1264
1265 self.attributes.insert(
1266 Attribute::AcpTargetScope,
1267 SchemaAttribute {
1268 name: Attribute::AcpTargetScope,
1269 uuid: UUID_SCHEMA_ATTR_ACP_TARGETSCOPE,
1270 description: String::from(
1271 "The effective targets of the ACP, e.g. what will be acted upon.",
1272 ),
1273 multivalue: false,
1274 unique: false,
1275 phantom: false,
1276 sync_allowed: false,
1277 replicated: Replicated::True,
1278 indexed: true,
1279 syntax: SyntaxType::JsonFilter,
1280 },
1281 );
1282 self.attributes.insert(
1283 Attribute::AcpSearchAttr,
1284 SchemaAttribute {
1285 name: Attribute::AcpSearchAttr,
1286 uuid: UUID_SCHEMA_ATTR_ACP_SEARCH_ATTR,
1287 description: String::from(
1288 "The attributes that may be viewed or searched by the receiver on targetscope.",
1289 ),
1290 multivalue: true,
1291 unique: false,
1292 phantom: false,
1293 sync_allowed: false,
1294 replicated: Replicated::True,
1295 indexed: true,
1296 syntax: SyntaxType::Utf8StringInsensitive,
1297 },
1298 );
1299 self.attributes.insert(
1300 Attribute::AcpCreateClass,
1301 SchemaAttribute {
1302 name: Attribute::AcpCreateClass,
1303 uuid: UUID_SCHEMA_ATTR_ACP_CREATE_CLASS,
1304 description: String::from("The set of classes that can be created on a new entry."),
1305 multivalue: true,
1306 unique: false,
1307 phantom: false,
1308 sync_allowed: false,
1309 replicated: Replicated::True,
1310 indexed: true,
1311 syntax: SyntaxType::Utf8StringInsensitive,
1312 },
1313 );
1314 self.attributes.insert(
1315 Attribute::AcpCreateAttr,
1316 SchemaAttribute {
1317 name: Attribute::AcpCreateAttr,
1318 uuid: UUID_SCHEMA_ATTR_ACP_CREATE_ATTR,
1319 description: String::from(
1320 "The set of attribute types that can be created on an entry.",
1321 ),
1322 multivalue: true,
1323 unique: false,
1324 phantom: false,
1325 sync_allowed: false,
1326 replicated: Replicated::True,
1327 indexed: true,
1328 syntax: SyntaxType::Utf8StringInsensitive,
1329 },
1330 );
1331
1332 self.attributes.insert(
1333 Attribute::AcpModifyRemovedAttr,
1334 SchemaAttribute {
1335 name: Attribute::AcpModifyRemovedAttr,
1336 uuid: UUID_SCHEMA_ATTR_ACP_MODIFY_REMOVEDATTR,
1337 description: String::from(
1338 "The set of attribute types that could be removed or purged in a modification.",
1339 ),
1340 multivalue: true,
1341 unique: false,
1342 phantom: false,
1343 sync_allowed: false,
1344 replicated: Replicated::True,
1345 indexed: true,
1346 syntax: SyntaxType::Utf8StringInsensitive,
1347 },
1348 );
1349 self.attributes.insert(
1350 Attribute::AcpModifyPresentAttr,
1351 SchemaAttribute {
1352 name: Attribute::AcpModifyPresentAttr,
1353 uuid: UUID_SCHEMA_ATTR_ACP_MODIFY_PRESENTATTR,
1354 description: String::from(
1355 "The set of attribute types that could be added or asserted in a modification.",
1356 ),
1357 multivalue: true,
1358 unique: false,
1359 phantom: false,
1360 sync_allowed: false,
1361 replicated: Replicated::True,
1362 indexed: true,
1363 syntax: SyntaxType::Utf8StringInsensitive,
1364 },
1365 );
1366 self.attributes.insert(
1367 Attribute::AcpModifyClass,
1368 SchemaAttribute {
1369 name: Attribute::AcpModifyClass,
1370 uuid: UUID_SCHEMA_ATTR_ACP_MODIFY_CLASS,
1371 description: String::from("The set of class values that could be asserted or added to an entry. Only applies to modify::present operations on class."),
1372 multivalue: true,
1373 unique: false,
1374 phantom: false,
1375 sync_allowed: false,
1376 replicated: Replicated::True,
1377 indexed: true,
1378 syntax: SyntaxType::Utf8StringInsensitive,
1379 },
1380 );
1381 self.attributes.insert(
1382 Attribute::AcpModifyPresentClass,
1383 SchemaAttribute {
1384 name: Attribute::AcpModifyPresentClass,
1385 uuid: UUID_SCHEMA_ATTR_ACP_MODIFY_PRESENT_CLASS,
1386 description: String::from("The set of class values that could be asserted or added to an entry. Only applies to modify::present operations on class."),
1387 multivalue: true,
1388 unique: false,
1389 phantom: false,
1390 sync_allowed: false,
1391 replicated: Replicated::True,
1392 indexed: false,
1393 syntax: SyntaxType::Utf8StringInsensitive,
1394 },
1395 );
1396 self.attributes.insert(
1397 Attribute::AcpModifyRemoveClass,
1398 SchemaAttribute {
1399 name: Attribute::AcpModifyRemoveClass,
1400 uuid: UUID_SCHEMA_ATTR_ACP_MODIFY_REMOVE_CLASS,
1401 description: String::from("The set of class values that could be asserted or added to an entry. Only applies to modify::remove operations on class."),
1402 multivalue: true,
1403 unique: false,
1404 phantom: false,
1405 sync_allowed: false,
1406 replicated: Replicated::True,
1407 indexed: false,
1408 syntax: SyntaxType::Utf8StringInsensitive,
1409 },
1410 );
1411 self.attributes.insert(
1412 Attribute::EntryManagedBy,
1413 SchemaAttribute {
1414 name: Attribute::EntryManagedBy,
1415 uuid: UUID_SCHEMA_ATTR_ENTRY_MANAGED_BY,
1416 description: String::from(
1417 "A reference to a group that has access to manage the content of this entry.",
1418 ),
1419 multivalue: false,
1420 unique: false,
1421 phantom: false,
1422 sync_allowed: false,
1423 replicated: Replicated::True,
1424 indexed: true,
1425 syntax: SyntaxType::ReferenceUuid,
1426 },
1427 );
1428 self.attributes.insert(
1430 Attribute::MemberOf,
1431 SchemaAttribute {
1432 name: Attribute::MemberOf,
1433 uuid: UUID_SCHEMA_ATTR_MEMBEROF,
1434 description: String::from("reverse group membership of the object"),
1435 multivalue: true,
1436 unique: false,
1437 phantom: false,
1438 sync_allowed: false,
1439 replicated: Replicated::False,
1440 indexed: true,
1441 syntax: SyntaxType::ReferenceUuid,
1442 },
1443 );
1444 self.attributes.insert(
1445 Attribute::DirectMemberOf,
1446 SchemaAttribute {
1447 name: Attribute::DirectMemberOf,
1448 uuid: UUID_SCHEMA_ATTR_DIRECTMEMBEROF,
1449 description: String::from("reverse direct group membership of the object"),
1450 multivalue: true,
1451 unique: false,
1452 phantom: false,
1453 sync_allowed: false,
1454 replicated: Replicated::False,
1455 indexed: true,
1456 syntax: SyntaxType::ReferenceUuid,
1457 },
1458 );
1459 self.attributes.insert(
1460 Attribute::RecycledDirectMemberOf,
1461 SchemaAttribute {
1462 name: Attribute::RecycledDirectMemberOf,
1463 uuid: UUID_SCHEMA_ATTR_RECYCLEDDIRECTMEMBEROF,
1464 description: String::from("recycled reverse direct group membership of the object to assist in revive operations."),
1465 multivalue: true,
1466 unique: false,
1467 phantom: false,
1468 sync_allowed: false,
1469 replicated: Replicated::True,
1474 indexed: true,
1475 syntax: SyntaxType::ReferenceUuid,
1476 },
1477 );
1478 self.attributes.insert(
1479 Attribute::Member,
1480 SchemaAttribute {
1481 name: Attribute::Member,
1482 uuid: UUID_SCHEMA_ATTR_MEMBER,
1483 description: String::from("List of members of the group"),
1484 multivalue: true,
1485 unique: false,
1486 phantom: false,
1487 sync_allowed: true,
1488 replicated: Replicated::True,
1489 indexed: true,
1490 syntax: SyntaxType::ReferenceUuid,
1491 },
1492 );
1493 self.attributes.insert(
1494 Attribute::DynMember,
1495 SchemaAttribute {
1496 name: Attribute::DynMember,
1497 uuid: UUID_SCHEMA_ATTR_DYNMEMBER,
1498 description: String::from("List of dynamic members of the group"),
1499 multivalue: true,
1500 unique: false,
1501 phantom: false,
1502 sync_allowed: true,
1503 replicated: Replicated::False,
1504 indexed: true,
1505 syntax: SyntaxType::ReferenceUuid,
1506 },
1507 );
1508
1509 self.attributes.insert(
1510 Attribute::Refers,
1511 SchemaAttribute {
1512 name: Attribute::Refers,
1513 uuid: UUID_SCHEMA_ATTR_REFERS,
1514 description: String::from("A reference to another object"),
1515 multivalue: false,
1516 unique: false,
1517 phantom: false,
1518 sync_allowed: false,
1519 replicated: Replicated::True,
1520 indexed: true,
1521 syntax: SyntaxType::ReferenceUuid,
1522 },
1523 );
1524
1525 self.attributes.insert(
1526 Attribute::CascadeDeleted,
1527 SchemaAttribute {
1528 name: Attribute::CascadeDeleted,
1529 uuid: UUID_SCHEMA_ATTR_CASCADE_DELETED,
1530 description: String::from("A marker attribute denoting that this entry was deleted by cascade when this UUID was deleted."),
1531 multivalue: false,
1532 unique: false,
1533 phantom: false,
1534 sync_allowed: false,
1535 replicated: Replicated::True,
1536 indexed: true,
1537 syntax: SyntaxType::Uuid,
1540 },
1541 );
1542
1543 self.attributes.insert(
1545 Attribute::Version,
1546 SchemaAttribute {
1547 name: Attribute::Version,
1548 uuid: UUID_SCHEMA_ATTR_VERSION,
1549 description: String::from(
1550 "The systems internal migration version for provided objects",
1551 ),
1552 multivalue: false,
1553 unique: false,
1554 phantom: false,
1555 sync_allowed: false,
1556 replicated: Replicated::True,
1557 indexed: false,
1558 syntax: SyntaxType::Uint32,
1559 },
1560 );
1561 self.attributes.insert(
1563 Attribute::Domain,
1564 SchemaAttribute {
1565 name: Attribute::Domain,
1566 uuid: UUID_SCHEMA_ATTR_DOMAIN,
1567 description: String::from("A DNS Domain name entry."),
1568 multivalue: true,
1569 unique: false,
1570 phantom: false,
1571 sync_allowed: false,
1572 replicated: Replicated::True,
1573 indexed: true,
1574 syntax: SyntaxType::Utf8StringIname,
1575 },
1576 );
1577 self.attributes.insert(
1578 Attribute::Claim,
1579 SchemaAttribute {
1580 name: Attribute::Claim,
1581 uuid: UUID_SCHEMA_ATTR_CLAIM,
1582 description: String::from(
1583 "The string identifier of an extracted claim that can be filtered",
1584 ),
1585 multivalue: true,
1586 unique: false,
1587 phantom: true,
1588 sync_allowed: false,
1589 replicated: Replicated::True,
1590 indexed: false,
1591 syntax: SyntaxType::Utf8StringInsensitive,
1592 },
1593 );
1594 self.attributes.insert(
1595 Attribute::Scope,
1596 SchemaAttribute {
1597 name: Attribute::Scope,
1598 uuid: UUID_SCHEMA_ATTR_SCOPE,
1599 description: String::from(
1600 "The string identifier of a permission scope in a session",
1601 ),
1602 multivalue: true,
1603 unique: false,
1604 phantom: true,
1605 sync_allowed: false,
1606 replicated: Replicated::True,
1607 indexed: false,
1608 syntax: SyntaxType::Utf8StringInsensitive,
1609 },
1610 );
1611
1612 self.attributes.insert(
1614 Attribute::SyncExternalId,
1615 SchemaAttribute {
1616 name: Attribute::SyncExternalId,
1617 uuid: UUID_SCHEMA_ATTR_SYNC_EXTERNAL_ID,
1618 description: String::from(
1619 "An external string ID of an entry imported from a sync agreement",
1620 ),
1621 multivalue: false,
1622 unique: true,
1623 phantom: false,
1624 sync_allowed: false,
1625 replicated: Replicated::True,
1626 indexed: true,
1627 syntax: SyntaxType::Utf8StringInsensitive,
1628 },
1629 );
1630 self.attributes.insert(
1631 Attribute::SyncParentUuid,
1632 SchemaAttribute {
1633 name: Attribute::SyncParentUuid,
1634 uuid: UUID_SCHEMA_ATTR_SYNC_PARENT_UUID,
1635 description: String::from(
1636 "The UUID of the parent sync agreement that created this entry.",
1637 ),
1638 multivalue: false,
1639 unique: false,
1640 phantom: false,
1641 sync_allowed: false,
1642 replicated: Replicated::True,
1643 indexed: true,
1644 syntax: SyntaxType::ReferenceUuid,
1645 },
1646 );
1647 self.attributes.insert(
1648 Attribute::SyncClass,
1649 SchemaAttribute {
1650 name: Attribute::SyncClass,
1651 uuid: UUID_SCHEMA_ATTR_SYNC_CLASS,
1652 description: String::from("The set of classes requested by the sync client."),
1653 multivalue: true,
1654 unique: false,
1655 phantom: false,
1656 sync_allowed: false,
1657 replicated: Replicated::True,
1658 indexed: false,
1659 syntax: SyntaxType::Utf8StringInsensitive,
1660 },
1661 );
1662
1663 self.attributes.insert(
1664 Attribute::PasswordImport,
1665 SchemaAttribute {
1666 name: Attribute::PasswordImport,
1667 uuid: UUID_SCHEMA_ATTR_PASSWORD_IMPORT,
1668 description: String::from("An imported password hash from an external system."),
1669 multivalue: false,
1670 unique: false,
1671 phantom: true,
1672 sync_allowed: true,
1673 replicated: Replicated::False,
1674 indexed: false,
1675 syntax: SyntaxType::Utf8String,
1676 },
1677 );
1678
1679 self.attributes.insert(
1680 Attribute::UnixPasswordImport,
1681 SchemaAttribute {
1682 name: Attribute::UnixPasswordImport,
1683 uuid: UUID_SCHEMA_ATTR_UNIX_PASSWORD_IMPORT,
1684 description: String::from(
1685 "An imported unix password hash from an external system.",
1686 ),
1687 multivalue: false,
1688 unique: false,
1689 phantom: true,
1690 sync_allowed: true,
1691 replicated: Replicated::False,
1692 indexed: false,
1693 syntax: SyntaxType::Utf8String,
1694 },
1695 );
1696
1697 self.attributes.insert(
1698 Attribute::TotpImport,
1699 SchemaAttribute {
1700 name: Attribute::TotpImport,
1701 uuid: UUID_SCHEMA_ATTR_TOTP_IMPORT,
1702 description: String::from("An imported totp secret from an external system."),
1703 multivalue: true,
1704 unique: false,
1705 phantom: true,
1706 sync_allowed: true,
1707 replicated: Replicated::False,
1708 indexed: false,
1709 syntax: SyntaxType::TotpSecret,
1710 },
1711 );
1712
1713 self.attributes.insert(
1715 Attribute::Dn,
1716 SchemaAttribute {
1717 name: Attribute::Dn,
1718 uuid: UUID_SCHEMA_ATTR_DN,
1719 description: String::from("An LDAP Compatible DN"),
1720 multivalue: false,
1721 unique: false,
1722 phantom: true,
1723 sync_allowed: false,
1724 replicated: Replicated::False,
1725 indexed: false,
1726 syntax: SyntaxType::Utf8StringInsensitive,
1727 },
1728 );
1729 self.attributes.insert(
1730 Attribute::EntryDn,
1731 SchemaAttribute {
1732 name: Attribute::EntryDn,
1733 uuid: UUID_SCHEMA_ATTR_ENTRYDN,
1734 description: String::from("An LDAP Compatible EntryDN"),
1735 multivalue: false,
1736 unique: false,
1737 phantom: true,
1738 sync_allowed: false,
1739 replicated: Replicated::False,
1740 indexed: false,
1741 syntax: SyntaxType::Utf8StringInsensitive,
1742 },
1743 );
1744 self.attributes.insert(
1745 Attribute::EntryUuid,
1746 SchemaAttribute {
1747 name: Attribute::EntryUuid,
1748 uuid: UUID_SCHEMA_ATTR_ENTRYUUID,
1749 description: String::from("An LDAP Compatible entryUUID"),
1750 multivalue: false,
1751 unique: false,
1752 phantom: true,
1753 sync_allowed: false,
1754 replicated: Replicated::False,
1755 indexed: false,
1756 syntax: SyntaxType::Uuid,
1757 },
1758 );
1759 self.attributes.insert(
1760 Attribute::ObjectClass,
1761 SchemaAttribute {
1762 name: Attribute::ObjectClass,
1763 uuid: UUID_SCHEMA_ATTR_OBJECTCLASS,
1764 description: String::from("An LDAP Compatible objectClass"),
1765 multivalue: true,
1766 unique: false,
1767 phantom: true,
1768 sync_allowed: false,
1769 replicated: Replicated::False,
1770 indexed: false,
1771 syntax: SyntaxType::Utf8StringInsensitive,
1772 },
1773 );
1774 self.attributes.insert(
1775 Attribute::Cn,
1776 SchemaAttribute {
1777 name: Attribute::Cn,
1778 uuid: UUID_SCHEMA_ATTR_CN,
1779 description: String::from("An LDAP Compatible objectClass"),
1780 multivalue: false,
1781 unique: false,
1782 phantom: true,
1783 sync_allowed: false,
1784 replicated: Replicated::False,
1785 indexed: false,
1786 syntax: SyntaxType::Utf8StringIname,
1787 },
1788 );
1789 self.attributes.insert(
1790 Attribute::LdapKeys, SchemaAttribute {
1792 name: Attribute::LdapKeys, uuid: UUID_SCHEMA_ATTR_KEYS,
1794 description: String::from("An LDAP Compatible keys (ssh)"),
1795 multivalue: true,
1796 unique: false,
1797 phantom: true,
1798 sync_allowed: false,
1799 replicated: Replicated::False,
1800 indexed: false,
1801 syntax: SyntaxType::SshKey,
1802 },
1803 );
1804 self.attributes.insert(
1805 Attribute::LdapSshPublicKey,
1806 SchemaAttribute {
1807 name: Attribute::LdapSshPublicKey,
1808 uuid: UUID_SCHEMA_ATTR_SSHPUBLICKEY,
1809 description: String::from("An LDAP Compatible sshPublicKey"),
1810 multivalue: true,
1811 unique: false,
1812 phantom: true,
1813 sync_allowed: false,
1814 replicated: Replicated::False,
1815 indexed: false,
1816 syntax: SyntaxType::SshKey,
1817 },
1818 );
1819 self.attributes.insert(
1820 Attribute::Email,
1821 SchemaAttribute {
1822 name: Attribute::Email,
1823 uuid: UUID_SCHEMA_ATTR_EMAIL,
1824 description: String::from("An LDAP Compatible email"),
1825 multivalue: true,
1826 unique: false,
1827 phantom: true,
1828 sync_allowed: false,
1829 replicated: Replicated::False,
1830 indexed: false,
1831 syntax: SyntaxType::EmailAddress,
1832 },
1833 );
1834 self.attributes.insert(
1835 Attribute::EmailPrimary,
1836 SchemaAttribute {
1837 name: Attribute::EmailPrimary,
1838 uuid: UUID_SCHEMA_ATTR_EMAILPRIMARY,
1839 description: String::from("An LDAP Compatible primary email"),
1840 multivalue: false,
1841 unique: false,
1842 phantom: true,
1843 sync_allowed: false,
1844 replicated: Replicated::False,
1845 indexed: false,
1846 syntax: SyntaxType::EmailAddress,
1847 },
1848 );
1849 self.attributes.insert(
1850 Attribute::EmailAlternative,
1851 SchemaAttribute {
1852 name: Attribute::EmailAlternative,
1853 uuid: UUID_SCHEMA_ATTR_EMAILALTERNATIVE,
1854 description: String::from("An LDAP Compatible alternative email"),
1855 multivalue: false,
1856 unique: false,
1857 phantom: true,
1858 sync_allowed: false,
1859 replicated: Replicated::False,
1860 indexed: false,
1861 syntax: SyntaxType::EmailAddress,
1862 },
1863 );
1864 self.attributes.insert(
1865 Attribute::LdapEmailAddress,
1866 SchemaAttribute {
1867 name: Attribute::LdapEmailAddress,
1868 uuid: UUID_SCHEMA_ATTR_EMAILADDRESS,
1869 description: String::from("An LDAP Compatible emailAddress"),
1870 multivalue: true,
1871 unique: false,
1872 phantom: true,
1873 sync_allowed: false,
1874 replicated: Replicated::False,
1875 indexed: false,
1876 syntax: SyntaxType::EmailAddress,
1877 },
1878 );
1879 self.attributes.insert(
1880 Attribute::Gecos,
1881 SchemaAttribute {
1882 name: Attribute::Gecos,
1883 uuid: UUID_SCHEMA_ATTR_GECOS,
1884 description: String::from("An LDAP Compatible gecos."),
1885 multivalue: false,
1886 unique: false,
1887 phantom: true,
1888 sync_allowed: false,
1889 replicated: Replicated::False,
1890 indexed: false,
1891 syntax: SyntaxType::Utf8String,
1892 },
1893 );
1894 self.attributes.insert(
1895 Attribute::Uid,
1896 SchemaAttribute {
1897 name: Attribute::Uid,
1898 uuid: UUID_SCHEMA_ATTR_UID,
1899 description: String::from("An LDAP Compatible uid."),
1900 multivalue: false,
1901 unique: false,
1902 phantom: true,
1903 sync_allowed: false,
1904 replicated: Replicated::False,
1905 indexed: false,
1906 syntax: SyntaxType::Utf8String,
1907 },
1908 );
1909 self.attributes.insert(
1910 Attribute::UidNumber,
1911 SchemaAttribute {
1912 name: Attribute::UidNumber,
1913 uuid: UUID_SCHEMA_ATTR_UIDNUMBER,
1914 description: String::from("An LDAP Compatible uidNumber."),
1915 multivalue: false,
1916 unique: false,
1917 phantom: true,
1918 sync_allowed: false,
1919 replicated: Replicated::False,
1920 indexed: false,
1921 syntax: SyntaxType::Uint32,
1922 },
1923 );
1924 self.attributes.insert(
1925 Attribute::SudoHost,
1926 SchemaAttribute {
1927 name: Attribute::SudoHost,
1928 uuid: UUID_SCHEMA_ATTR_SUDOHOST,
1929 description: String::from("An LDAP Compatible sudohost."),
1930 multivalue: false,
1931 unique: false,
1932 phantom: true,
1933 sync_allowed: false,
1934 replicated: Replicated::False,
1935 indexed: false,
1936 syntax: SyntaxType::Utf8String,
1937 },
1938 );
1939 self.classes.insert(
1946 EntryClass::AttributeType.into(),
1947 SchemaClass {
1948 name: EntryClass::AttributeType.into(),
1949 uuid: UUID_SCHEMA_CLASS_ATTRIBUTETYPE,
1950 description: String::from("Definition of a schema attribute"),
1951 systemmay: vec![
1952 Attribute::Replicated,
1953 Attribute::Phantom,
1954 Attribute::SyncAllowed,
1955 Attribute::Index,
1956 Attribute::Indexed,
1957 ],
1958 systemmust: vec![
1959 Attribute::Class,
1960 Attribute::AttributeName,
1961 Attribute::MultiValue,
1962 Attribute::Unique,
1963 Attribute::Syntax,
1964 Attribute::Description,
1965 ],
1966 systemexcludes: vec![EntryClass::ClassType.into()],
1967 ..Default::default()
1968 },
1969 );
1970 self.classes.insert(
1971 EntryClass::ClassType.into(),
1972 SchemaClass {
1973 name: EntryClass::ClassType.into(),
1974 uuid: UUID_SCHEMA_CLASS_CLASSTYPE,
1975 description: String::from("Definition of a schema classtype"),
1976 systemmay: vec![
1977 Attribute::SyncAllowed,
1978 Attribute::SystemMay,
1979 Attribute::May,
1980 Attribute::SystemMust,
1981 Attribute::Must,
1982 Attribute::SystemSupplements,
1983 Attribute::Supplements,
1984 Attribute::SystemExcludes,
1985 Attribute::Excludes,
1986 ],
1987 systemmust: vec![
1988 Attribute::Class,
1989 Attribute::ClassName,
1990 Attribute::Description,
1991 ],
1992 systemexcludes: vec![Attribute::AttributeType.into()],
1993 ..Default::default()
1994 },
1995 );
1996 self.classes.insert(
1997 EntryClass::Object.into(),
1998 SchemaClass {
1999 name: EntryClass::Object.into(),
2000 uuid: UUID_SCHEMA_CLASS_OBJECT,
2001 description: String::from("A system created class that all objects must contain"),
2002 systemmay: vec![Attribute::Description, Attribute::EntryManagedBy],
2003 systemmust: vec![
2004 Attribute::Class,
2005 Attribute::Uuid,
2006 Attribute::LastModifiedCid,
2007 Attribute::CreatedAtCid,
2008 ],
2009 ..Default::default()
2010 },
2011 );
2012 self.classes.insert(
2013 EntryClass::Builtin.into(),
2014 SchemaClass {
2015 name: EntryClass::Builtin.into(),
2016 uuid: UUID_SCHEMA_CLASS_BUILTIN,
2017 description: String::from("A marker class denoting builtin entries"),
2018 ..Default::default()
2019 },
2020 );
2021 self.classes.insert(
2022 EntryClass::MemberOf.into(),
2023 SchemaClass {
2024 name: EntryClass::MemberOf.into(),
2025 uuid: UUID_SCHEMA_CLASS_MEMBEROF,
2026 description: String::from(
2027 "Class that is dynamically added to recipients of memberof or directmemberof",
2028 ),
2029 systemmay: vec![Attribute::MemberOf, Attribute::DirectMemberOf],
2030 ..Default::default()
2031 },
2032 );
2033 self.classes.insert(
2034 EntryClass::ExtensibleObject.into(),
2035 SchemaClass {
2036 name: EntryClass::ExtensibleObject.into(),
2037 uuid: UUID_SCHEMA_CLASS_EXTENSIBLEOBJECT,
2038 description: String::from(
2039 "A class type that has green hair and turns off all rules ...",
2040 ),
2041 ..Default::default()
2042 },
2043 );
2044 self.classes.insert(
2046 EntryClass::Recycled.into(),
2047 SchemaClass {
2048 name: EntryClass::Recycled.into(),
2049 uuid: UUID_SCHEMA_CLASS_RECYCLED,
2050 description: String::from("An object that has been deleted, but still recoverable via the revive operation. Recycled objects are not modifiable, only revivable."),
2051 systemmay: vec![Attribute::RecycledDirectMemberOf, Attribute::CascadeDeleted],
2052 .. Default::default()
2053 },
2054 );
2055 self.classes.insert(
2056 EntryClass::Tombstone.into(),
2057 SchemaClass {
2058 name: EntryClass::Tombstone.into(),
2059 uuid: UUID_SCHEMA_CLASS_TOMBSTONE,
2060 description: String::from("An object that is purged from the recycle bin. This is a system internal state. Tombstones have no attributes beside UUID."),
2061 systemmust: vec![
2062 Attribute::Class,
2063 Attribute::Uuid,
2064 ],
2065 .. Default::default()
2066 },
2067 );
2068 self.classes.insert(
2069 EntryClass::Conflict.into(),
2070 SchemaClass {
2071 name: EntryClass::Conflict.into(),
2072 uuid: UUID_SCHEMA_CLASS_CONFLICT,
2073 description: String::from(
2074 "An entry representing conflicts that occurred during replication",
2075 ),
2076 systemmust: vec![Attribute::SourceUuid],
2077 systemsupplements: vec![EntryClass::Recycled.into()],
2078 ..Default::default()
2079 },
2080 );
2081 self.classes.insert(
2083 EntryClass::SystemInfo.into(),
2084 SchemaClass {
2085 name: EntryClass::SystemInfo.into(),
2086 uuid: UUID_SCHEMA_CLASS_SYSTEM_INFO,
2087 description: String::from("System metadata object class"),
2088 systemmust: vec![Attribute::Version],
2089 ..Default::default()
2090 },
2091 );
2092 self.classes.insert(
2094 EntryClass::AccessControlSearch.into(),
2095 SchemaClass {
2096 name: EntryClass::AccessControlSearch.into(),
2097 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_SEARCH,
2098 description: String::from("System Access Control Search Class"),
2099 systemmust: vec![Attribute::AcpSearchAttr],
2100 ..Default::default()
2101 },
2102 );
2103 self.classes.insert(
2104 EntryClass::AccessControlDelete.into(),
2105 SchemaClass {
2106 name: EntryClass::AccessControlDelete.into(),
2107 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_DELETE,
2108 description: String::from("System Access Control DELETE Class"),
2109 ..Default::default()
2110 },
2111 );
2112 self.classes.insert(
2113 EntryClass::AccessControlModify.into(),
2114 SchemaClass {
2115 name: EntryClass::AccessControlModify.into(),
2116 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_MODIFY,
2117 description: String::from("System Access Control Modify Class"),
2118 systemmay: vec![
2119 Attribute::AcpModifyRemovedAttr,
2120 Attribute::AcpModifyPresentAttr,
2121 Attribute::AcpModifyClass,
2122 Attribute::AcpModifyPresentClass,
2123 Attribute::AcpModifyRemoveClass,
2124 ],
2125 ..Default::default()
2126 },
2127 );
2128 self.classes.insert(
2129 EntryClass::AccessControlCreate.into(),
2130 SchemaClass {
2131 name: EntryClass::AccessControlCreate.into(),
2132 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_CREATE,
2133 description: String::from("System Access Control Create Class"),
2134 systemmay: vec![Attribute::AcpCreateClass, Attribute::AcpCreateAttr],
2135 ..Default::default()
2136 },
2137 );
2138 self.classes.insert(
2139 EntryClass::AccessControlProfile.into(),
2140 SchemaClass {
2141 name: EntryClass::AccessControlProfile.into(),
2142 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_PROFILE,
2143 description: String::from("System Access Control Profile Class"),
2144 systemmay: vec![Attribute::AcpEnable, Attribute::Description],
2145 systemmust: vec![Attribute::Name],
2146 systemsupplements: vec![
2147 EntryClass::AccessControlSearch.into(),
2148 EntryClass::AccessControlDelete.into(),
2149 EntryClass::AccessControlModify.into(),
2150 EntryClass::AccessControlCreate.into(),
2151 ],
2152 ..Default::default()
2153 },
2154 );
2155 self.classes.insert(
2156 EntryClass::AccessControlReceiverEntryManager.into(),
2157 SchemaClass {
2158 name: EntryClass::AccessControlReceiverEntryManager.into(),
2159 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_ENTRY_MANAGER,
2160 description: String::from("System Access Control Profile Receiver - Entry Manager"),
2161 systemexcludes: vec![EntryClass::AccessControlReceiverGroup.into()],
2162 systemsupplements: vec![EntryClass::AccessControlProfile.into()],
2163 ..Default::default()
2164 },
2165 );
2166 self.classes.insert(
2167 EntryClass::AccessControlReceiverGroup.into(),
2168 SchemaClass {
2169 name: EntryClass::AccessControlReceiverGroup.into(),
2170 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_GROUP,
2171 description: String::from("System Access Control Profile Receiver - Group"),
2172 systemmay: vec![Attribute::AcpReceiver],
2173 systemmust: vec![Attribute::AcpReceiverGroup],
2174 systemsupplements: vec![EntryClass::AccessControlProfile.into()],
2175 systemexcludes: vec![EntryClass::AccessControlReceiverEntryManager.into()],
2176 ..Default::default()
2177 },
2178 );
2179 self.classes.insert(
2180 EntryClass::AccessControlTargetScope.into(),
2181 SchemaClass {
2182 name: EntryClass::AccessControlTargetScope.into(),
2183 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_TARGET_SCOPE,
2184 description: String::from("System Access Control Profile Target - Scope"),
2185 systemmust: vec![Attribute::AcpTargetScope],
2186 systemsupplements: vec![EntryClass::AccessControlProfile.into()],
2187 ..Default::default()
2188 },
2189 );
2190
2191 self.classes.insert(
2193 EntryClass::System.into(),
2194 SchemaClass {
2195 name: EntryClass::System.into(),
2196 uuid: UUID_SCHEMA_CLASS_SYSTEM,
2197 description: String::from("A class denoting that a type is system generated and protected. It has special internal behaviour."),
2198 .. Default::default()
2199 },
2200 );
2201 self.classes.insert(
2202 EntryClass::SyncObject.into(),
2203 SchemaClass {
2204 name: EntryClass::SyncObject.into(),
2205 uuid: UUID_SCHEMA_CLASS_SYNC_OBJECT,
2206 description: String::from("A class denoting that an entry is synchronised from an external source. This entry may not be modifiable."),
2207 systemmust: vec![
2208 Attribute::SyncParentUuid
2209 ],
2210 systemmay: vec![
2211 Attribute::SyncExternalId,
2212 Attribute::SyncClass,
2213 ],
2214 .. Default::default()
2215 },
2216 );
2217
2218 let r = self.validate();
2219 if r.is_empty() {
2220 admin_debug!("schema validate -> passed");
2221 Ok(())
2222 } else {
2223 admin_error!(err = ?r, "schema validate -> errors");
2224 Err(OperationError::ConsistencyError(
2225 r.into_iter().filter_map(|v| v.err()).collect(),
2226 ))
2227 }
2228 }
2229}
2230
2231impl SchemaTransaction for SchemaWriteTransaction<'_> {
2232 fn get_attributes_unique(&self) -> &Vec<Attribute> {
2233 &self.unique_cache
2234 }
2235
2236 fn get_reference_types(&self) -> &HashMap<Attribute, SchemaAttribute> {
2237 &self.ref_cache
2238 }
2239
2240 fn get_classes(&self) -> &HashMap<AttrString, SchemaClass> {
2241 &self.classes
2242 }
2243
2244 fn get_attributes(&self) -> &HashMap<Attribute, SchemaAttribute> {
2245 &self.attributes
2246 }
2247}
2248
2249impl SchemaTransaction for SchemaReadTransaction {
2250 fn get_attributes_unique(&self) -> &Vec<Attribute> {
2251 &self.unique_cache
2252 }
2253
2254 fn get_reference_types(&self) -> &HashMap<Attribute, SchemaAttribute> {
2255 &self.ref_cache
2256 }
2257
2258 fn get_classes(&self) -> &HashMap<AttrString, SchemaClass> {
2259 &self.classes
2260 }
2261
2262 fn get_attributes(&self) -> &HashMap<Attribute, SchemaAttribute> {
2263 &self.attributes
2264 }
2265}
2266
2267impl Schema {
2268 pub fn new() -> Result<Self, OperationError> {
2269 let s = Schema {
2270 classes: CowCell::new(HashMap::with_capacity(128)),
2271 attributes: CowCell::new(HashMap::with_capacity(128)),
2272 unique_cache: CowCell::new(Vec::with_capacity(0)),
2273 ref_cache: CowCell::new(HashMap::with_capacity(64)),
2274 };
2275 let mut sw = s.write();
2277 let r1 = sw.generate_in_memory();
2278 debug_assert!(r1.is_ok());
2279 r1?;
2280 let r2 = sw.commit().map(|_| s);
2281 debug_assert!(r2.is_ok());
2282 r2
2283 }
2284
2285 pub fn read(&self) -> SchemaReadTransaction {
2286 SchemaReadTransaction {
2287 classes: self.classes.read(),
2288 attributes: self.attributes.read(),
2289 unique_cache: self.unique_cache.read(),
2290 ref_cache: self.ref_cache.read(),
2291 }
2292 }
2293
2294 pub fn write(&self) -> SchemaWriteTransaction<'_> {
2295 SchemaWriteTransaction {
2296 classes: self.classes.write(),
2297 attributes: self.attributes.write(),
2298 unique_cache: self.unique_cache.write(),
2299 ref_cache: self.ref_cache.write(),
2300 }
2301 }
2302
2303 #[cfg(test)]
2304 pub(crate) fn write_blocking(&self) -> SchemaWriteTransaction<'_> {
2305 self.write()
2306 }
2307}
2308
2309#[cfg(test)]
2310mod tests {
2311 use crate::prelude::*;
2312 use crate::schema::{Schema, SchemaAttribute, SchemaClass, SchemaTransaction, SyntaxType};
2313 use uuid::Uuid;
2314
2315 macro_rules! validate_schema {
2318 ($sch:ident) => {{
2319 let r: Result<Vec<()>, ConsistencyError> = $sch.validate().into_iter().collect();
2321 assert!(r.is_ok());
2322 }};
2323 }
2324
2325 macro_rules! sch_from_entry_ok {
2326 (
2327 $e:expr,
2328 $type:ty
2329 ) => {{
2330 let ev1 = $e.into_sealed_committed();
2331
2332 let r1 = <$type>::try_from(&ev1);
2333 assert!(r1.is_ok());
2334 }};
2335 }
2336
2337 macro_rules! sch_from_entry_err {
2338 (
2339 $e:expr,
2340 $type:ty
2341 ) => {{
2342 let ev1 = $e.into_sealed_committed();
2343
2344 let r1 = <$type>::try_from(&ev1);
2345 assert!(r1.is_err());
2346 }};
2347 }
2348
2349 #[test]
2350 fn test_schema_attribute_from_entry() {
2351 sketching::test_init();
2352
2353 sch_from_entry_err!(
2354 entry_init!(
2355 (Attribute::Class, EntryClass::Object.to_value()),
2356 (Attribute::Class, EntryClass::AttributeType.to_value()),
2357 (
2358 Attribute::AttributeName,
2359 Value::new_iutf8("schema_attr_test")
2360 ),
2361 (
2362 Attribute::Uuid,
2363 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2364 ),
2365 (Attribute::Unique, Value::Bool(false))
2366 ),
2367 SchemaAttribute
2368 );
2369
2370 sch_from_entry_err!(
2371 entry_init!(
2372 (Attribute::Class, EntryClass::Object.to_value()),
2373 (Attribute::Class, EntryClass::AttributeType.to_value()),
2374 (
2375 Attribute::AttributeName,
2376 Value::new_iutf8("schema_attr_test")
2377 ),
2378 (
2379 Attribute::Uuid,
2380 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2381 ),
2382 (Attribute::MultiValue, Value::Bool(false)),
2383 (Attribute::Unique, Value::Bool(false)),
2384 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String))
2385 ),
2386 SchemaAttribute
2387 );
2388
2389 sch_from_entry_err!(
2390 entry_init!(
2391 (Attribute::Class, EntryClass::Object.to_value()),
2392 (Attribute::Class, EntryClass::AttributeType.to_value()),
2393 (
2394 Attribute::AttributeName,
2395 Value::new_iutf8("schema_attr_test")
2396 ),
2397 (
2398 Attribute::Uuid,
2399 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2400 ),
2401 (
2402 Attribute::Description,
2403 Value::Utf8("Test attr parsing".to_string())
2404 ),
2405 (Attribute::MultiValue, Value::Utf8("htouaoeu".to_string())),
2406 (Attribute::Unique, Value::Bool(false)),
2407 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String))
2408 ),
2409 SchemaAttribute
2410 );
2411
2412 sch_from_entry_err!(
2413 entry_init!(
2414 (Attribute::Class, EntryClass::Object.to_value()),
2415 (Attribute::Class, EntryClass::AttributeType.to_value()),
2416 (
2417 Attribute::AttributeName,
2418 Value::new_iutf8("schema_attr_test")
2419 ),
2420 (
2421 Attribute::Uuid,
2422 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2423 ),
2424 (
2425 Attribute::Description,
2426 Value::Utf8("Test attr parsing".to_string())
2427 ),
2428 (Attribute::MultiValue, Value::Bool(false)),
2429 (Attribute::Unique, Value::Bool(false)),
2430 (Attribute::Syntax, Value::Utf8("TNEOUNTUH".to_string()))
2431 ),
2432 SchemaAttribute
2433 );
2434
2435 sch_from_entry_ok!(
2437 entry_init!(
2438 (Attribute::Class, EntryClass::Object.to_value()),
2439 (Attribute::Class, EntryClass::AttributeType.to_value()),
2440 (
2441 Attribute::AttributeName,
2442 Value::new_iutf8("schema_attr_test")
2443 ),
2444 (
2445 Attribute::Uuid,
2446 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2447 ),
2448 (
2449 Attribute::Description,
2450 Value::Utf8("Test attr parsing".to_string())
2451 ),
2452 (Attribute::MultiValue, Value::Bool(false)),
2453 (Attribute::Unique, Value::Bool(false)),
2454 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String))
2455 ),
2456 SchemaAttribute
2457 );
2458
2459 sch_from_entry_ok!(
2461 entry_init!(
2462 (Attribute::Class, EntryClass::Object.to_value()),
2463 (Attribute::Class, EntryClass::AttributeType.to_value()),
2464 (
2465 Attribute::AttributeName,
2466 Value::new_iutf8("schema_attr_test")
2467 ),
2468 (
2469 Attribute::Uuid,
2470 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2471 ),
2472 (
2473 Attribute::Description,
2474 Value::Utf8("Test attr parsing".to_string())
2475 ),
2476 (Attribute::MultiValue, Value::Bool(false)),
2477 (Attribute::Unique, Value::Bool(false)),
2478 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2479 (Attribute::Index, Value::Bool(true))
2480 ),
2481 SchemaAttribute
2482 );
2483 }
2484
2485 #[test]
2486 fn test_schema_class_from_entry() {
2487 sch_from_entry_err!(
2488 entry_init!(
2489 (Attribute::Class, EntryClass::Object.to_value()),
2490 (Attribute::Class, EntryClass::ClassType.to_value()),
2491 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2492 (
2493 Attribute::Uuid,
2494 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2495 )
2496 ),
2497 SchemaClass
2498 );
2499
2500 sch_from_entry_err!(
2501 entry_init!(
2502 (Attribute::Class, EntryClass::Object.to_value()),
2503 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2504 (
2505 Attribute::Uuid,
2506 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2507 ),
2508 (
2509 Attribute::Description,
2510 Value::Utf8("class test".to_string())
2511 )
2512 ),
2513 SchemaClass
2514 );
2515
2516 sch_from_entry_ok!(
2518 entry_init!(
2519 (Attribute::Class, EntryClass::Object.to_value()),
2520 (Attribute::Class, EntryClass::ClassType.to_value()),
2521 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2522 (
2523 Attribute::Uuid,
2524 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2525 ),
2526 (
2527 Attribute::Description,
2528 Value::Utf8("class test".to_string())
2529 )
2530 ),
2531 SchemaClass
2532 );
2533
2534 sch_from_entry_ok!(
2536 entry_init!(
2537 (Attribute::Class, EntryClass::Object.to_value()),
2538 (Attribute::Class, EntryClass::ClassType.to_value()),
2539 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2540 (
2541 Attribute::Uuid,
2542 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2543 ),
2544 (
2545 Attribute::Description,
2546 Value::Utf8("class test".to_string())
2547 ),
2548 (Attribute::SystemMust, Value::new_iutf8("a"))
2549 ),
2550 SchemaClass
2551 );
2552
2553 sch_from_entry_ok!(
2554 entry_init!(
2555 (Attribute::Class, EntryClass::Object.to_value()),
2556 (Attribute::Class, EntryClass::ClassType.to_value()),
2557 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2558 (
2559 Attribute::Uuid,
2560 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2561 ),
2562 (
2563 Attribute::Description,
2564 Value::Utf8("class test".to_string())
2565 ),
2566 (Attribute::SystemMay, Value::new_iutf8("a"))
2567 ),
2568 SchemaClass
2569 );
2570
2571 sch_from_entry_ok!(
2572 entry_init!(
2573 (Attribute::Class, EntryClass::Object.to_value()),
2574 (Attribute::Class, EntryClass::ClassType.to_value()),
2575 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2576 (
2577 Attribute::Uuid,
2578 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2579 ),
2580 (
2581 Attribute::Description,
2582 Value::Utf8("class test".to_string())
2583 ),
2584 (Attribute::May, Value::new_iutf8("a")),
2585 (Attribute::Must, Value::new_iutf8("b"))
2586 ),
2587 SchemaClass
2588 );
2589
2590 sch_from_entry_ok!(
2591 entry_init!(
2592 (Attribute::Class, EntryClass::Object.to_value()),
2593 (Attribute::Class, EntryClass::ClassType.to_value()),
2594 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2595 (
2596 Attribute::Uuid,
2597 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2598 ),
2599 (
2600 Attribute::Description,
2601 Value::Utf8("class test".to_string())
2602 ),
2603 (Attribute::May, Value::new_iutf8("a")),
2604 (Attribute::Must, Value::new_iutf8("b")),
2605 (Attribute::SystemMay, Value::new_iutf8("c")),
2606 (Attribute::SystemMust, Value::new_iutf8("d"))
2607 ),
2608 SchemaClass
2609 );
2610 }
2611
2612 #[test]
2613 fn test_schema_attribute_simple() {
2614 let single_value_string = SchemaAttribute {
2618 name: Attribute::from("single_value"),
2619 uuid: Uuid::new_v4(),
2620 description: String::from(""),
2621 syntax: SyntaxType::Utf8StringInsensitive,
2622 ..Default::default()
2623 };
2624
2625 let r1 = single_value_string
2626 .validate_ava(&Attribute::from("single_value"), &(vs_iutf8!["test"] as _));
2627 assert_eq!(r1, Ok(()));
2628
2629 let rvs = vs_iutf8!["test1", "test2"] as _;
2630 let r2 = single_value_string.validate_ava(&Attribute::from("single_value"), &rvs);
2631 assert_eq!(
2632 r2,
2633 Err(SchemaError::InvalidAttributeSyntax(
2634 "single_value".to_string()
2635 ))
2636 );
2637
2638 let multi_value_string = SchemaAttribute {
2641 name: Attribute::from("mv_string"),
2642 uuid: Uuid::new_v4(),
2643 description: String::from(""),
2644 multivalue: true,
2645 syntax: SyntaxType::Utf8String,
2646 ..Default::default()
2647 };
2648
2649 let rvs = vs_utf8!["test1".to_string(), "test2".to_string()] as _;
2650 let r5 = multi_value_string.validate_ava(&Attribute::from("mv_string"), &rvs);
2651 assert_eq!(r5, Ok(()));
2652
2653 let multi_value_boolean = SchemaAttribute {
2654 name: Attribute::from("mv_bool"),
2655 uuid: Uuid::new_v4(),
2656 description: String::from(""),
2657 multivalue: true,
2658 syntax: SyntaxType::Boolean,
2659 ..Default::default()
2660 };
2661
2662 let rvs = vs_bool![true, false];
2679 let r4 = multi_value_boolean.validate_ava(&Attribute::from("mv_bool"), &(rvs as _));
2680 assert_eq!(r4, Ok(()));
2681
2682 let single_value_syntax = SchemaAttribute {
2684 name: Attribute::from("sv_syntax"),
2685 uuid: Uuid::new_v4(),
2686 description: String::from(""),
2687 syntax: SyntaxType::SyntaxId,
2688 ..Default::default()
2689 };
2690
2691 let rvs = vs_syntax![SyntaxType::try_from("UTF8STRING").unwrap()] as _;
2692 let r6 = single_value_syntax.validate_ava(&Attribute::from("sv_syntax"), &rvs);
2693 assert_eq!(r6, Ok(()));
2694
2695 let rvs = vs_utf8!["thaeountaheu".to_string()] as _;
2696 let r7 = single_value_syntax.validate_ava(&Attribute::from("sv_syntax"), &rvs);
2697 assert_eq!(
2698 r7,
2699 Err(SchemaError::InvalidAttributeSyntax("sv_syntax".to_string()))
2700 );
2701
2702 let single_value_index = SchemaAttribute {
2703 name: Attribute::from("sv_index"),
2704 uuid: Uuid::new_v4(),
2705 description: String::from(""),
2706 syntax: SyntaxType::IndexId,
2707 ..Default::default()
2708 };
2709
2710 let rvs = vs_utf8!["thaeountaheu".to_string()] as _;
2711 let r9 = single_value_index.validate_ava(&Attribute::from("sv_index"), &rvs);
2712 assert_eq!(
2713 r9,
2714 Err(SchemaError::InvalidAttributeSyntax("sv_index".to_string()))
2715 );
2716 }
2717
2718 #[test]
2719 fn test_schema_simple() {
2720 let schema = Schema::new().expect("failed to create schema");
2721 let schema_ro = schema.read();
2722 validate_schema!(schema_ro);
2723 }
2724
2725 #[test]
2726 fn test_schema_entries() {
2727 sketching::test_init();
2728 let schema_outer = Schema::new().expect("failed to create schema");
2731 let schema = schema_outer.read();
2732
2733 let e_no_uuid = entry_init!().into_invalid_new();
2734
2735 assert_eq!(
2736 e_no_uuid.validate(&schema),
2737 Err(SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
2738 );
2739
2740 let e_no_class = entry_init!((
2741 Attribute::Uuid,
2742 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2743 ))
2744 .into_invalid_new();
2745
2746 assert_eq!(e_no_class.validate(&schema), Err(SchemaError::NoClassFound));
2747
2748 let e_bad_class = entry_init!(
2749 (
2750 Attribute::Uuid,
2751 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2752 ),
2753 (Attribute::Class, Value::new_iutf8("zzzzzz"))
2754 )
2755 .into_invalid_new();
2756 assert_eq!(
2757 e_bad_class.validate(&schema),
2758 Err(SchemaError::InvalidClass(vec!["zzzzzz".to_string()]))
2759 );
2760
2761 let e_attr_invalid = entry_init!(
2762 (
2763 Attribute::Uuid,
2764 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2765 ),
2766 (Attribute::Class, EntryClass::Object.to_value()),
2767 (Attribute::Class, EntryClass::AttributeType.to_value())
2768 )
2769 .into_invalid_new();
2770 let res = e_attr_invalid.validate(&schema);
2771 matches!(res, Err(SchemaError::MissingMustAttribute(_)));
2772
2773 let e_attr_invalid_may = entry_init!(
2774 (Attribute::Class, EntryClass::Object.to_value()),
2775 (Attribute::Class, EntryClass::AttributeType.to_value()),
2776 (Attribute::AttributeName, Value::new_iutf8("testattr")),
2777 (Attribute::Description, Value::Utf8("testattr".to_string())),
2778 (Attribute::MultiValue, Value::Bool(false)),
2779 (Attribute::Unique, Value::Bool(false)),
2780 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2781 (
2782 Attribute::Uuid,
2783 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2784 ),
2785 (Attribute::TestAttr, Value::Utf8("zzzz".to_string()))
2786 )
2787 .into_invalid_new();
2788
2789 assert_eq!(
2790 e_attr_invalid_may.validate(&schema),
2791 Err(SchemaError::AttributeNotValidForClass(
2792 Attribute::TestAttr.to_string()
2793 ))
2794 );
2795
2796 let e_attr_invalid_syn = entry_init!(
2797 (Attribute::Class, EntryClass::Object.to_value()),
2798 (Attribute::Class, EntryClass::AttributeType.to_value()),
2799 (Attribute::AttributeName, Value::new_iutf8("testattr")),
2800 (Attribute::Description, Value::Utf8("testattr".to_string())),
2801 (Attribute::MultiValue, Value::Utf8("false".to_string())),
2802 (Attribute::Unique, Value::Bool(false)),
2803 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2804 (
2805 Attribute::Uuid,
2806 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2807 )
2808 )
2809 .into_invalid_new();
2810
2811 assert_eq!(
2812 e_attr_invalid_syn.validate(&schema),
2813 Err(SchemaError::InvalidAttributeSyntax(
2814 "multivalue".to_string()
2815 ))
2816 );
2817
2818 let e_phantom = entry_init!(
2820 (Attribute::Class, EntryClass::Object.to_value()),
2821 (Attribute::Class, EntryClass::AttributeType.to_value()),
2822 (Attribute::AttributeName, Value::new_iutf8("testattr")),
2823 (Attribute::Description, Value::Utf8("testattr".to_string())),
2824 (Attribute::MultiValue, Value::Bool(false)),
2825 (Attribute::Unique, Value::Bool(false)),
2826 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2827 (
2828 Attribute::Uuid,
2829 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2830 ),
2831 (
2832 Attribute::PasswordImport,
2833 Value::Utf8("password".to_string())
2834 )
2835 )
2836 .into_invalid_new();
2837 assert!(e_phantom.validate(&schema).is_err());
2838
2839 let e_ok = entry_init!(
2840 (Attribute::Class, EntryClass::Object.to_value()),
2841 (Attribute::Class, EntryClass::AttributeType.to_value()),
2842 (Attribute::AttributeName, Value::new_iutf8("testattr")),
2843 (Attribute::Description, Value::Utf8("testattr".to_string())),
2844 (Attribute::MultiValue, Value::Bool(true)),
2845 (Attribute::Unique, Value::Bool(false)),
2846 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2847 (
2848 Attribute::Uuid,
2849 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2850 )
2851 )
2852 .into_invalid_new();
2853 assert!(e_ok.validate(&schema).is_ok());
2854 }
2855
2856 #[test]
2857 fn test_schema_extensible() {
2858 let schema_outer = Schema::new().expect("failed to create schema");
2859 let schema = schema_outer.read();
2860 let e_extensible_bad = entry_init!(
2862 (Attribute::Class, EntryClass::ExtensibleObject.to_value()),
2863 (
2864 Attribute::Uuid,
2865 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2866 ),
2867 (Attribute::MultiValue, Value::Utf8("zzzz".to_string()))
2868 )
2869 .into_invalid_new();
2870
2871 assert_eq!(
2872 e_extensible_bad.validate(&schema),
2873 Err(SchemaError::InvalidAttributeSyntax(
2874 "multivalue".to_string()
2875 ))
2876 );
2877
2878 let e_extensible_phantom = entry_init!(
2880 (Attribute::Class, EntryClass::ExtensibleObject.to_value()),
2881 (
2882 Attribute::Uuid,
2883 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2884 ),
2885 (Attribute::PasswordImport, Value::Utf8("zzzz".to_string()))
2886 )
2887 .into_invalid_new();
2888
2889 assert_eq!(
2890 e_extensible_phantom.validate(&schema),
2891 Err(SchemaError::PhantomAttribute(
2892 Attribute::PasswordImport.to_string()
2893 ))
2894 );
2895
2896 let e_extensible = entry_init!(
2897 (Attribute::Class, EntryClass::ExtensibleObject.to_value()),
2898 (
2899 Attribute::Uuid,
2900 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2901 ),
2902 (Attribute::MultiValue, Value::Bool(true))
2903 )
2904 .into_invalid_new();
2905
2906 assert!(e_extensible.validate(&schema).is_ok());
2908 }
2909
2910 #[test]
2911 fn test_schema_filter_validation() {
2912 let schema_outer = Schema::new().expect("failed to create schema");
2913 let schema = schema_outer.read();
2914
2915 let f_bool = filter_all!(f_eq(Attribute::MultiValue, PartialValue::new_iutf8("zzzz")));
2917 assert_eq!(
2918 f_bool.validate(&schema),
2919 Err(SchemaError::InvalidAttributeSyntax(
2920 "multivalue".to_string()
2921 ))
2922 );
2923 let f_insense = filter_all!(f_eq(Attribute::Class, EntryClass::AttributeType.into()));
2925 assert_eq!(
2926 f_insense.validate(&schema),
2927 Ok(filter_valid!(f_eq(
2928 Attribute::Class,
2929 EntryClass::AttributeType.into()
2930 )))
2931 );
2932 let f_or_empty = filter_all!(f_or!([]));
2934 assert_eq!(f_or_empty.validate(&schema), Err(SchemaError::EmptyFilter));
2935 let f_or = filter_all!(f_or!([f_eq(
2936 Attribute::MultiValue,
2937 PartialValue::new_iutf8("zzzz")
2938 )]));
2939 assert_eq!(
2940 f_or.validate(&schema),
2941 Err(SchemaError::InvalidAttributeSyntax(
2942 "multivalue".to_string()
2943 ))
2944 );
2945 let f_or_mult = filter_all!(f_and!([
2946 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
2947 f_eq(Attribute::MultiValue, PartialValue::new_iutf8("zzzzzzz")),
2948 ]));
2949 assert_eq!(
2950 f_or_mult.validate(&schema),
2951 Err(SchemaError::InvalidAttributeSyntax(
2952 "multivalue".to_string()
2953 ))
2954 );
2955 let f_or_ok = filter_all!(f_andnot(f_and!([
2957 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
2958 f_sub(Attribute::Class, EntryClass::ClassType.into()),
2959 f_pres(Attribute::Class)
2960 ])));
2961 assert_eq!(
2962 f_or_ok.validate(&schema),
2963 Ok(filter_valid!(f_andnot(f_and!([
2964 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
2965 f_sub(Attribute::Class, EntryClass::ClassType.into()),
2966 f_pres(Attribute::Class)
2967 ]))))
2968 );
2969 }
2970
2971 #[test]
2972 fn test_schema_class_phantom_reject() {
2973 let schema_outer = Schema::new().expect("failed to create schema");
2975 let mut schema = schema_outer.write_blocking();
2976
2977 assert!(schema.validate().is_empty());
2978
2979 let class = SchemaClass {
2981 name: AttrString::from("testobject"),
2982 uuid: Uuid::new_v4(),
2983 description: String::from("test object"),
2984 systemmay: vec![Attribute::Claim],
2985 ..Default::default()
2986 };
2987
2988 assert!(schema.update_classes(vec![class]).is_ok());
2989
2990 assert_eq!(schema.validate().len(), 1);
2991 }
2992
2993 #[test]
2994 fn test_schema_class_exclusion_requires() {
2995 sketching::test_init();
2996
2997 let schema_outer = Schema::new().expect("failed to create schema");
2998 let mut schema = schema_outer.write_blocking();
2999
3000 assert!(schema.validate().is_empty());
3001
3002 let class_account = SchemaClass {
3005 name: Attribute::Account.into(),
3006 uuid: Uuid::new_v4(),
3007 description: String::from("account object"),
3008 systemmust: vec![
3009 Attribute::Class,
3010 Attribute::Uuid,
3011 Attribute::LastModifiedCid,
3012 Attribute::CreatedAtCid,
3013 ],
3014 systemsupplements: vec![EntryClass::Service.into(), EntryClass::Person.into()],
3015 ..Default::default()
3016 };
3017
3018 let class_person = SchemaClass {
3019 name: EntryClass::Person.into(),
3020 uuid: Uuid::new_v4(),
3021 description: String::from("person object"),
3022 systemmust: vec![
3023 Attribute::Class,
3024 Attribute::Uuid,
3025 Attribute::LastModifiedCid,
3026 Attribute::CreatedAtCid,
3027 ],
3028 ..Default::default()
3029 };
3030
3031 let class_service = SchemaClass {
3032 name: EntryClass::Service.into(),
3033 uuid: Uuid::new_v4(),
3034 description: String::from("service object"),
3035 systemmust: vec![
3036 Attribute::Class,
3037 Attribute::Uuid,
3038 Attribute::LastModifiedCid,
3039 Attribute::CreatedAtCid,
3040 ],
3041 excludes: vec![EntryClass::Person.into()],
3042 ..Default::default()
3043 };
3044
3045 assert!(schema
3046 .update_classes(vec![class_account, class_person, class_service])
3047 .is_ok());
3048
3049 let e_account = entry_init!(
3051 (Attribute::Class, EntryClass::Account.to_value()),
3052 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3053 )
3054 .into_invalid_new();
3055
3056 assert_eq!(
3057 e_account.validate(&schema),
3058 Err(SchemaError::SupplementsNotSatisfied(vec![
3059 EntryClass::Service.into(),
3060 EntryClass::Person.into(),
3061 ]))
3062 );
3063
3064 let e_service_person = entry_init!(
3079 (Attribute::Class, EntryClass::Service.to_value()),
3080 (Attribute::Class, EntryClass::Account.to_value()),
3081 (Attribute::Class, EntryClass::Person.to_value()),
3082 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3083 )
3084 .into_invalid_new();
3085
3086 assert_eq!(
3087 e_service_person.validate(&schema),
3088 Err(SchemaError::ExcludesNotSatisfied(vec![
3089 EntryClass::Person.to_string()
3090 ]))
3091 );
3092
3093 let e_service_valid = entry_init!(
3095 (Attribute::Class, EntryClass::Service.to_value()),
3096 (Attribute::Class, EntryClass::Account.to_value()),
3097 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3098 )
3099 .into_invalid_new();
3100
3101 assert!(e_service_valid.validate(&schema).is_ok());
3102
3103 let e_person_valid = entry_init!(
3104 (Attribute::Class, EntryClass::Person.to_value()),
3105 (Attribute::Class, EntryClass::Account.to_value()),
3106 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3107 )
3108 .into_invalid_new();
3109
3110 assert!(e_person_valid.validate(&schema).is_ok());
3111
3112 let e_person_valid = entry_init!(
3113 (Attribute::Class, EntryClass::Person.to_value()),
3114 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3115 )
3116 .into_invalid_new();
3117
3118 assert!(e_person_valid.validate(&schema).is_ok());
3119 }
3120}