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