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![Attribute::Description, Attribute::EntryManagedBy],
2019 systemmust: vec![
2020 Attribute::Class,
2021 Attribute::Uuid,
2022 Attribute::LastModifiedCid,
2023 Attribute::CreatedAtCid,
2024 ],
2025 ..Default::default()
2026 },
2027 );
2028 self.classes.insert(
2029 EntryClass::Builtin.into(),
2030 SchemaClass {
2031 name: EntryClass::Builtin.into(),
2032 uuid: UUID_SCHEMA_CLASS_BUILTIN,
2033 description: String::from("A marker class denoting builtin entries"),
2034 ..Default::default()
2035 },
2036 );
2037 self.classes.insert(
2038 EntryClass::MemberOf.into(),
2039 SchemaClass {
2040 name: EntryClass::MemberOf.into(),
2041 uuid: UUID_SCHEMA_CLASS_MEMBEROF,
2042 description: String::from(
2043 "Class that is dynamically added to recipients of memberof or directmemberof",
2044 ),
2045 systemmay: vec![Attribute::MemberOf, Attribute::DirectMemberOf],
2046 ..Default::default()
2047 },
2048 );
2049 self.classes.insert(
2050 EntryClass::ExtensibleObject.into(),
2051 SchemaClass {
2052 name: EntryClass::ExtensibleObject.into(),
2053 uuid: UUID_SCHEMA_CLASS_EXTENSIBLEOBJECT,
2054 description: String::from(
2055 "A class type that has green hair and turns off all rules ...",
2056 ),
2057 ..Default::default()
2058 },
2059 );
2060 self.classes.insert(
2062 EntryClass::Recycled.into(),
2063 SchemaClass {
2064 name: EntryClass::Recycled.into(),
2065 uuid: UUID_SCHEMA_CLASS_RECYCLED,
2066 description: String::from("An object that has been deleted, but still recoverable via the revive operation. Recycled objects are not modifiable, only revivable."),
2067 systemmay: vec![Attribute::RecycledDirectMemberOf, Attribute::CascadeDeleted],
2068 .. Default::default()
2069 },
2070 );
2071 self.classes.insert(
2072 EntryClass::Tombstone.into(),
2073 SchemaClass {
2074 name: EntryClass::Tombstone.into(),
2075 uuid: UUID_SCHEMA_CLASS_TOMBSTONE,
2076 description: String::from("An object that is purged from the recycle bin. This is a system internal state. Tombstones have no attributes beside UUID."),
2077 systemmust: vec![
2078 Attribute::Class,
2079 Attribute::Uuid,
2080 ],
2081 .. Default::default()
2082 },
2083 );
2084 self.classes.insert(
2085 EntryClass::Conflict.into(),
2086 SchemaClass {
2087 name: EntryClass::Conflict.into(),
2088 uuid: UUID_SCHEMA_CLASS_CONFLICT,
2089 description: String::from(
2090 "An entry representing conflicts that occurred during replication",
2091 ),
2092 systemmust: vec![Attribute::SourceUuid],
2093 systemsupplements: vec![EntryClass::Recycled.into()],
2094 ..Default::default()
2095 },
2096 );
2097 self.classes.insert(
2099 EntryClass::SystemInfo.into(),
2100 SchemaClass {
2101 name: EntryClass::SystemInfo.into(),
2102 uuid: UUID_SCHEMA_CLASS_SYSTEM_INFO,
2103 description: String::from("System metadata object class"),
2104 systemmust: vec![Attribute::Version],
2105 ..Default::default()
2106 },
2107 );
2108 self.classes.insert(
2110 EntryClass::AccessControlSearch.into(),
2111 SchemaClass {
2112 name: EntryClass::AccessControlSearch.into(),
2113 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_SEARCH,
2114 description: String::from("System Access Control Search Class"),
2115 systemmust: vec![Attribute::AcpSearchAttr],
2116 ..Default::default()
2117 },
2118 );
2119 self.classes.insert(
2120 EntryClass::AccessControlDelete.into(),
2121 SchemaClass {
2122 name: EntryClass::AccessControlDelete.into(),
2123 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_DELETE,
2124 description: String::from("System Access Control DELETE Class"),
2125 ..Default::default()
2126 },
2127 );
2128 self.classes.insert(
2129 EntryClass::AccessControlModify.into(),
2130 SchemaClass {
2131 name: EntryClass::AccessControlModify.into(),
2132 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_MODIFY,
2133 description: String::from("System Access Control Modify Class"),
2134 systemmay: vec![
2135 Attribute::AcpModifyRemovedAttr,
2136 Attribute::AcpModifyPresentAttr,
2137 Attribute::AcpModifyClass,
2138 Attribute::AcpModifyPresentClass,
2139 Attribute::AcpModifyRemoveClass,
2140 ],
2141 ..Default::default()
2142 },
2143 );
2144 self.classes.insert(
2145 EntryClass::AccessControlCreate.into(),
2146 SchemaClass {
2147 name: EntryClass::AccessControlCreate.into(),
2148 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_CREATE,
2149 description: String::from("System Access Control Create Class"),
2150 systemmay: vec![Attribute::AcpCreateClass, Attribute::AcpCreateAttr],
2151 ..Default::default()
2152 },
2153 );
2154 self.classes.insert(
2155 EntryClass::AccessControlProfile.into(),
2156 SchemaClass {
2157 name: EntryClass::AccessControlProfile.into(),
2158 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_PROFILE,
2159 description: String::from("System Access Control Profile Class"),
2160 systemmay: vec![Attribute::AcpEnable, Attribute::Description],
2161 systemmust: vec![Attribute::Name],
2162 systemsupplements: vec![
2163 EntryClass::AccessControlSearch.into(),
2164 EntryClass::AccessControlDelete.into(),
2165 EntryClass::AccessControlModify.into(),
2166 EntryClass::AccessControlCreate.into(),
2167 ],
2168 ..Default::default()
2169 },
2170 );
2171 self.classes.insert(
2172 EntryClass::AccessControlReceiverEntryManager.into(),
2173 SchemaClass {
2174 name: EntryClass::AccessControlReceiverEntryManager.into(),
2175 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_ENTRY_MANAGER,
2176 description: String::from("System Access Control Profile Receiver - Entry Manager"),
2177 systemexcludes: vec![EntryClass::AccessControlReceiverGroup.into()],
2178 systemsupplements: vec![EntryClass::AccessControlProfile.into()],
2179 ..Default::default()
2180 },
2181 );
2182 self.classes.insert(
2183 EntryClass::AccessControlReceiverGroup.into(),
2184 SchemaClass {
2185 name: EntryClass::AccessControlReceiverGroup.into(),
2186 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_RECEIVER_GROUP,
2187 description: String::from("System Access Control Profile Receiver - Group"),
2188 systemmay: vec![Attribute::AcpReceiver],
2189 systemmust: vec![Attribute::AcpReceiverGroup],
2190 systemsupplements: vec![EntryClass::AccessControlProfile.into()],
2191 systemexcludes: vec![EntryClass::AccessControlReceiverEntryManager.into()],
2192 ..Default::default()
2193 },
2194 );
2195 self.classes.insert(
2196 EntryClass::AccessControlTargetScope.into(),
2197 SchemaClass {
2198 name: EntryClass::AccessControlTargetScope.into(),
2199 uuid: UUID_SCHEMA_CLASS_ACCESS_CONTROL_TARGET_SCOPE,
2200 description: String::from("System Access Control Profile Target - Scope"),
2201 systemmust: vec![Attribute::AcpTargetScope],
2202 systemsupplements: vec![EntryClass::AccessControlProfile.into()],
2203 ..Default::default()
2204 },
2205 );
2206
2207 self.classes.insert(
2209 EntryClass::System.into(),
2210 SchemaClass {
2211 name: EntryClass::System.into(),
2212 uuid: UUID_SCHEMA_CLASS_SYSTEM,
2213 description: String::from("A class denoting that a type is system generated and protected. It has special internal behaviour."),
2214 .. Default::default()
2215 },
2216 );
2217 self.classes.insert(
2218 EntryClass::SyncObject.into(),
2219 SchemaClass {
2220 name: EntryClass::SyncObject.into(),
2221 uuid: UUID_SCHEMA_CLASS_SYNC_OBJECT,
2222 description: String::from("A class denoting that an entry is synchronised from an external source. This entry may not be modifiable."),
2223 systemmust: vec![
2224 Attribute::SyncParentUuid
2225 ],
2226 systemmay: vec![
2227 Attribute::SyncExternalId,
2228 Attribute::SyncClass,
2229 ],
2230 .. Default::default()
2231 },
2232 );
2233
2234 let r = self.validate();
2235 if r.is_empty() {
2236 admin_debug!("schema validate -> passed");
2237 Ok(())
2238 } else {
2239 admin_error!(err = ?r, "schema validate -> errors");
2240 Err(OperationError::ConsistencyError(
2241 r.into_iter().filter_map(|v| v.err()).collect(),
2242 ))
2243 }
2244 }
2245}
2246
2247impl SchemaTransaction for SchemaWriteTransaction<'_> {
2248 fn get_attributes_unique(&self) -> &Vec<Attribute> {
2249 &self.unique_cache
2250 }
2251
2252 fn get_reference_types(&self) -> &HashMap<Attribute, SchemaAttribute> {
2253 &self.ref_cache
2254 }
2255
2256 fn get_classes(&self) -> &HashMap<AttrString, SchemaClass> {
2257 &self.classes
2258 }
2259
2260 fn get_attributes(&self) -> &HashMap<Attribute, SchemaAttribute> {
2261 &self.attributes
2262 }
2263}
2264
2265impl SchemaTransaction for SchemaReadTransaction {
2266 fn get_attributes_unique(&self) -> &Vec<Attribute> {
2267 &self.unique_cache
2268 }
2269
2270 fn get_reference_types(&self) -> &HashMap<Attribute, SchemaAttribute> {
2271 &self.ref_cache
2272 }
2273
2274 fn get_classes(&self) -> &HashMap<AttrString, SchemaClass> {
2275 &self.classes
2276 }
2277
2278 fn get_attributes(&self) -> &HashMap<Attribute, SchemaAttribute> {
2279 &self.attributes
2280 }
2281}
2282
2283impl Schema {
2284 pub fn new() -> Result<Self, OperationError> {
2285 let s = Schema {
2286 classes: CowCell::new(HashMap::with_capacity(128)),
2287 attributes: CowCell::new(HashMap::with_capacity(128)),
2288 unique_cache: CowCell::new(Vec::with_capacity(0)),
2289 ref_cache: CowCell::new(HashMap::with_capacity(64)),
2290 };
2291 let mut sw = s.write();
2293 let r1 = sw.generate_in_memory();
2294 debug_assert!(r1.is_ok());
2295 r1?;
2296 let r2 = sw.commit().map(|_| s);
2297 debug_assert!(r2.is_ok());
2298 r2
2299 }
2300
2301 pub fn read(&self) -> SchemaReadTransaction {
2302 SchemaReadTransaction {
2303 classes: self.classes.read(),
2304 attributes: self.attributes.read(),
2305 unique_cache: self.unique_cache.read(),
2306 ref_cache: self.ref_cache.read(),
2307 }
2308 }
2309
2310 pub fn write(&self) -> SchemaWriteTransaction<'_> {
2311 SchemaWriteTransaction {
2312 classes: self.classes.write(),
2313 attributes: self.attributes.write(),
2314 unique_cache: self.unique_cache.write(),
2315 ref_cache: self.ref_cache.write(),
2316 }
2317 }
2318
2319 #[cfg(test)]
2320 pub(crate) fn write_blocking(&self) -> SchemaWriteTransaction<'_> {
2321 self.write()
2322 }
2323}
2324
2325#[cfg(test)]
2326mod tests {
2327 use crate::prelude::*;
2328 use crate::schema::{Schema, SchemaAttribute, SchemaClass, SchemaTransaction, SyntaxType};
2329 use uuid::Uuid;
2330
2331 macro_rules! validate_schema {
2334 ($sch:ident) => {{
2335 let r: Result<Vec<()>, ConsistencyError> = $sch.validate().into_iter().collect();
2337 assert!(r.is_ok());
2338 }};
2339 }
2340
2341 macro_rules! sch_from_entry_ok {
2342 (
2343 $e:expr,
2344 $type:ty
2345 ) => {{
2346 let ev1 = $e.into_sealed_committed();
2347
2348 let r1 = <$type>::try_from(&ev1);
2349 assert!(r1.is_ok());
2350 }};
2351 }
2352
2353 macro_rules! sch_from_entry_err {
2354 (
2355 $e:expr,
2356 $type:ty
2357 ) => {{
2358 let ev1 = $e.into_sealed_committed();
2359
2360 let r1 = <$type>::try_from(&ev1);
2361 assert!(r1.is_err());
2362 }};
2363 }
2364
2365 #[test]
2366 fn test_schema_attribute_from_entry() {
2367 sketching::test_init();
2368
2369 sch_from_entry_err!(
2370 entry_init!(
2371 (Attribute::Class, EntryClass::Object.to_value()),
2372 (Attribute::Class, EntryClass::AttributeType.to_value()),
2373 (
2374 Attribute::AttributeName,
2375 Value::new_iutf8("schema_attr_test")
2376 ),
2377 (
2378 Attribute::Uuid,
2379 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2380 ),
2381 (Attribute::Unique, Value::Bool(false))
2382 ),
2383 SchemaAttribute
2384 );
2385
2386 sch_from_entry_err!(
2387 entry_init!(
2388 (Attribute::Class, EntryClass::Object.to_value()),
2389 (Attribute::Class, EntryClass::AttributeType.to_value()),
2390 (
2391 Attribute::AttributeName,
2392 Value::new_iutf8("schema_attr_test")
2393 ),
2394 (
2395 Attribute::Uuid,
2396 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2397 ),
2398 (Attribute::MultiValue, Value::Bool(false)),
2399 (Attribute::Unique, Value::Bool(false)),
2400 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String))
2401 ),
2402 SchemaAttribute
2403 );
2404
2405 sch_from_entry_err!(
2406 entry_init!(
2407 (Attribute::Class, EntryClass::Object.to_value()),
2408 (Attribute::Class, EntryClass::AttributeType.to_value()),
2409 (
2410 Attribute::AttributeName,
2411 Value::new_iutf8("schema_attr_test")
2412 ),
2413 (
2414 Attribute::Uuid,
2415 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2416 ),
2417 (
2418 Attribute::Description,
2419 Value::Utf8("Test attr parsing".to_string())
2420 ),
2421 (Attribute::MultiValue, Value::Utf8("htouaoeu".to_string())),
2422 (Attribute::Unique, Value::Bool(false)),
2423 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String))
2424 ),
2425 SchemaAttribute
2426 );
2427
2428 sch_from_entry_err!(
2429 entry_init!(
2430 (Attribute::Class, EntryClass::Object.to_value()),
2431 (Attribute::Class, EntryClass::AttributeType.to_value()),
2432 (
2433 Attribute::AttributeName,
2434 Value::new_iutf8("schema_attr_test")
2435 ),
2436 (
2437 Attribute::Uuid,
2438 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2439 ),
2440 (
2441 Attribute::Description,
2442 Value::Utf8("Test attr parsing".to_string())
2443 ),
2444 (Attribute::MultiValue, Value::Bool(false)),
2445 (Attribute::Unique, Value::Bool(false)),
2446 (Attribute::Syntax, Value::Utf8("TNEOUNTUH".to_string()))
2447 ),
2448 SchemaAttribute
2449 );
2450
2451 sch_from_entry_ok!(
2453 entry_init!(
2454 (Attribute::Class, EntryClass::Object.to_value()),
2455 (Attribute::Class, EntryClass::AttributeType.to_value()),
2456 (
2457 Attribute::AttributeName,
2458 Value::new_iutf8("schema_attr_test")
2459 ),
2460 (
2461 Attribute::Uuid,
2462 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2463 ),
2464 (
2465 Attribute::Description,
2466 Value::Utf8("Test attr parsing".to_string())
2467 ),
2468 (Attribute::MultiValue, Value::Bool(false)),
2469 (Attribute::Unique, Value::Bool(false)),
2470 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String))
2471 ),
2472 SchemaAttribute
2473 );
2474
2475 sch_from_entry_ok!(
2477 entry_init!(
2478 (Attribute::Class, EntryClass::Object.to_value()),
2479 (Attribute::Class, EntryClass::AttributeType.to_value()),
2480 (
2481 Attribute::AttributeName,
2482 Value::new_iutf8("schema_attr_test")
2483 ),
2484 (
2485 Attribute::Uuid,
2486 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2487 ),
2488 (
2489 Attribute::Description,
2490 Value::Utf8("Test attr parsing".to_string())
2491 ),
2492 (Attribute::MultiValue, Value::Bool(false)),
2493 (Attribute::Unique, Value::Bool(false)),
2494 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2495 (Attribute::Index, Value::Bool(true))
2496 ),
2497 SchemaAttribute
2498 );
2499 }
2500
2501 #[test]
2502 fn test_schema_class_from_entry() {
2503 sch_from_entry_err!(
2504 entry_init!(
2505 (Attribute::Class, EntryClass::Object.to_value()),
2506 (Attribute::Class, EntryClass::ClassType.to_value()),
2507 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2508 (
2509 Attribute::Uuid,
2510 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2511 )
2512 ),
2513 SchemaClass
2514 );
2515
2516 sch_from_entry_err!(
2517 entry_init!(
2518 (Attribute::Class, EntryClass::Object.to_value()),
2519 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2520 (
2521 Attribute::Uuid,
2522 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2523 ),
2524 (
2525 Attribute::Description,
2526 Value::Utf8("class test".to_string())
2527 )
2528 ),
2529 SchemaClass
2530 );
2531
2532 sch_from_entry_ok!(
2534 entry_init!(
2535 (Attribute::Class, EntryClass::Object.to_value()),
2536 (Attribute::Class, EntryClass::ClassType.to_value()),
2537 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2538 (
2539 Attribute::Uuid,
2540 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2541 ),
2542 (
2543 Attribute::Description,
2544 Value::Utf8("class test".to_string())
2545 )
2546 ),
2547 SchemaClass
2548 );
2549
2550 sch_from_entry_ok!(
2552 entry_init!(
2553 (Attribute::Class, EntryClass::Object.to_value()),
2554 (Attribute::Class, EntryClass::ClassType.to_value()),
2555 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2556 (
2557 Attribute::Uuid,
2558 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2559 ),
2560 (
2561 Attribute::Description,
2562 Value::Utf8("class test".to_string())
2563 ),
2564 (Attribute::SystemMust, Value::new_iutf8("a"))
2565 ),
2566 SchemaClass
2567 );
2568
2569 sch_from_entry_ok!(
2570 entry_init!(
2571 (Attribute::Class, EntryClass::Object.to_value()),
2572 (Attribute::Class, EntryClass::ClassType.to_value()),
2573 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2574 (
2575 Attribute::Uuid,
2576 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2577 ),
2578 (
2579 Attribute::Description,
2580 Value::Utf8("class test".to_string())
2581 ),
2582 (Attribute::SystemMay, Value::new_iutf8("a"))
2583 ),
2584 SchemaClass
2585 );
2586
2587 sch_from_entry_ok!(
2588 entry_init!(
2589 (Attribute::Class, EntryClass::Object.to_value()),
2590 (Attribute::Class, EntryClass::ClassType.to_value()),
2591 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2592 (
2593 Attribute::Uuid,
2594 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2595 ),
2596 (
2597 Attribute::Description,
2598 Value::Utf8("class test".to_string())
2599 ),
2600 (Attribute::May, Value::new_iutf8("a")),
2601 (Attribute::Must, Value::new_iutf8("b"))
2602 ),
2603 SchemaClass
2604 );
2605
2606 sch_from_entry_ok!(
2607 entry_init!(
2608 (Attribute::Class, EntryClass::Object.to_value()),
2609 (Attribute::Class, EntryClass::ClassType.to_value()),
2610 (Attribute::ClassName, Value::new_iutf8("schema_class_test")),
2611 (
2612 Attribute::Uuid,
2613 Value::Uuid(uuid::uuid!("66c68b2f-d02c-4243-8013-7946e40fe321"))
2614 ),
2615 (
2616 Attribute::Description,
2617 Value::Utf8("class test".to_string())
2618 ),
2619 (Attribute::May, Value::new_iutf8("a")),
2620 (Attribute::Must, Value::new_iutf8("b")),
2621 (Attribute::SystemMay, Value::new_iutf8("c")),
2622 (Attribute::SystemMust, Value::new_iutf8("d"))
2623 ),
2624 SchemaClass
2625 );
2626 }
2627
2628 #[test]
2629 fn test_schema_attribute_simple() {
2630 let single_value_string = SchemaAttribute {
2634 name: Attribute::from("single_value"),
2635 uuid: Uuid::new_v4(),
2636 description: String::from(""),
2637 syntax: SyntaxType::Utf8StringInsensitive,
2638 ..Default::default()
2639 };
2640
2641 let r1 = single_value_string
2642 .validate_ava(&Attribute::from("single_value"), &(vs_iutf8!["test"] as _));
2643 assert_eq!(r1, Ok(()));
2644
2645 let rvs = vs_iutf8!["test1", "test2"] as _;
2646 let r2 = single_value_string.validate_ava(&Attribute::from("single_value"), &rvs);
2647 assert_eq!(
2648 r2,
2649 Err(SchemaError::InvalidAttributeSyntax(
2650 "single_value".to_string()
2651 ))
2652 );
2653
2654 let multi_value_string = SchemaAttribute {
2657 name: Attribute::from("mv_string"),
2658 uuid: Uuid::new_v4(),
2659 description: String::from(""),
2660 multivalue: true,
2661 syntax: SyntaxType::Utf8String,
2662 ..Default::default()
2663 };
2664
2665 let rvs = vs_utf8!["test1".to_string(), "test2".to_string()] as _;
2666 let r5 = multi_value_string.validate_ava(&Attribute::from("mv_string"), &rvs);
2667 assert_eq!(r5, Ok(()));
2668
2669 let multi_value_boolean = SchemaAttribute {
2670 name: Attribute::from("mv_bool"),
2671 uuid: Uuid::new_v4(),
2672 description: String::from(""),
2673 multivalue: true,
2674 syntax: SyntaxType::Boolean,
2675 ..Default::default()
2676 };
2677
2678 let rvs = vs_bool![true, false];
2695 let r4 = multi_value_boolean.validate_ava(&Attribute::from("mv_bool"), &(rvs as _));
2696 assert_eq!(r4, Ok(()));
2697
2698 let single_value_syntax = SchemaAttribute {
2700 name: Attribute::from("sv_syntax"),
2701 uuid: Uuid::new_v4(),
2702 description: String::from(""),
2703 syntax: SyntaxType::SyntaxId,
2704 ..Default::default()
2705 };
2706
2707 let rvs = vs_syntax![SyntaxType::try_from("UTF8STRING").unwrap()] as _;
2708 let r6 = single_value_syntax.validate_ava(&Attribute::from("sv_syntax"), &rvs);
2709 assert_eq!(r6, Ok(()));
2710
2711 let rvs = vs_utf8!["thaeountaheu".to_string()] as _;
2712 let r7 = single_value_syntax.validate_ava(&Attribute::from("sv_syntax"), &rvs);
2713 assert_eq!(
2714 r7,
2715 Err(SchemaError::InvalidAttributeSyntax("sv_syntax".to_string()))
2716 );
2717
2718 let single_value_index = SchemaAttribute {
2719 name: Attribute::from("sv_index"),
2720 uuid: Uuid::new_v4(),
2721 description: String::from(""),
2722 syntax: SyntaxType::IndexId,
2723 ..Default::default()
2724 };
2725
2726 let rvs = vs_utf8!["thaeountaheu".to_string()] as _;
2727 let r9 = single_value_index.validate_ava(&Attribute::from("sv_index"), &rvs);
2728 assert_eq!(
2729 r9,
2730 Err(SchemaError::InvalidAttributeSyntax("sv_index".to_string()))
2731 );
2732 }
2733
2734 #[test]
2735 fn test_schema_simple() {
2736 let schema = Schema::new().expect("failed to create schema");
2737 let schema_ro = schema.read();
2738 validate_schema!(schema_ro);
2739 }
2740
2741 #[test]
2742 fn test_schema_entries() {
2743 sketching::test_init();
2744 let schema_outer = Schema::new().expect("failed to create schema");
2747 let schema = schema_outer.read();
2748
2749 let e_no_uuid = entry_init!().into_invalid_new();
2750
2751 assert_eq!(
2752 e_no_uuid.validate(&schema),
2753 Err(SchemaError::MissingMustAttribute(vec![Attribute::Uuid]))
2754 );
2755
2756 let e_no_class = entry_init!((
2757 Attribute::Uuid,
2758 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2759 ))
2760 .into_invalid_new();
2761
2762 assert_eq!(e_no_class.validate(&schema), Err(SchemaError::NoClassFound));
2763
2764 let e_bad_class = entry_init!(
2765 (
2766 Attribute::Uuid,
2767 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2768 ),
2769 (Attribute::Class, Value::new_iutf8("zzzzzz"))
2770 )
2771 .into_invalid_new();
2772 assert_eq!(
2773 e_bad_class.validate(&schema),
2774 Err(SchemaError::InvalidClass(vec!["zzzzzz".to_string()]))
2775 );
2776
2777 let e_attr_invalid = entry_init!(
2778 (
2779 Attribute::Uuid,
2780 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2781 ),
2782 (Attribute::Class, EntryClass::Object.to_value()),
2783 (Attribute::Class, EntryClass::AttributeType.to_value())
2784 )
2785 .into_invalid_new();
2786 let res = e_attr_invalid.validate(&schema);
2787 matches!(res, Err(SchemaError::MissingMustAttribute(_)));
2788
2789 let e_attr_invalid_may = entry_init!(
2790 (Attribute::Class, EntryClass::Object.to_value()),
2791 (Attribute::Class, EntryClass::AttributeType.to_value()),
2792 (Attribute::AttributeName, Value::new_iutf8("testattr")),
2793 (Attribute::Description, Value::Utf8("testattr".to_string())),
2794 (Attribute::MultiValue, Value::Bool(false)),
2795 (Attribute::Unique, Value::Bool(false)),
2796 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2797 (
2798 Attribute::Uuid,
2799 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2800 ),
2801 (Attribute::TestAttr, Value::Utf8("zzzz".to_string()))
2802 )
2803 .into_invalid_new();
2804
2805 assert_eq!(
2806 e_attr_invalid_may.validate(&schema),
2807 Err(SchemaError::AttributeNotValidForClass(
2808 Attribute::TestAttr.to_string()
2809 ))
2810 );
2811
2812 let e_attr_invalid_syn = entry_init!(
2813 (Attribute::Class, EntryClass::Object.to_value()),
2814 (Attribute::Class, EntryClass::AttributeType.to_value()),
2815 (Attribute::AttributeName, Value::new_iutf8("testattr")),
2816 (Attribute::Description, Value::Utf8("testattr".to_string())),
2817 (Attribute::MultiValue, Value::Utf8("false".to_string())),
2818 (Attribute::Unique, Value::Bool(false)),
2819 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2820 (
2821 Attribute::Uuid,
2822 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2823 )
2824 )
2825 .into_invalid_new();
2826
2827 assert_eq!(
2828 e_attr_invalid_syn.validate(&schema),
2829 Err(SchemaError::InvalidAttributeSyntax(
2830 "multivalue".to_string()
2831 ))
2832 );
2833
2834 let e_phantom = entry_init!(
2836 (Attribute::Class, EntryClass::Object.to_value()),
2837 (Attribute::Class, EntryClass::AttributeType.to_value()),
2838 (Attribute::AttributeName, Value::new_iutf8("testattr")),
2839 (Attribute::Description, Value::Utf8("testattr".to_string())),
2840 (Attribute::MultiValue, Value::Bool(false)),
2841 (Attribute::Unique, Value::Bool(false)),
2842 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2843 (
2844 Attribute::Uuid,
2845 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2846 ),
2847 (
2848 Attribute::PasswordImport,
2849 Value::Utf8("password".to_string())
2850 )
2851 )
2852 .into_invalid_new();
2853 assert!(e_phantom.validate(&schema).is_err());
2854
2855 let e_ok = entry_init!(
2856 (Attribute::Class, EntryClass::Object.to_value()),
2857 (Attribute::Class, EntryClass::AttributeType.to_value()),
2858 (Attribute::AttributeName, Value::new_iutf8("testattr")),
2859 (Attribute::Description, Value::Utf8("testattr".to_string())),
2860 (Attribute::MultiValue, Value::Bool(true)),
2861 (Attribute::Unique, Value::Bool(false)),
2862 (Attribute::Syntax, Value::Syntax(SyntaxType::Utf8String)),
2863 (
2864 Attribute::Uuid,
2865 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2866 )
2867 )
2868 .into_invalid_new();
2869 assert!(e_ok.validate(&schema).is_ok());
2870 }
2871
2872 #[test]
2873 fn test_schema_extensible() {
2874 let schema_outer = Schema::new().expect("failed to create schema");
2875 let schema = schema_outer.read();
2876 let e_extensible_bad = entry_init!(
2878 (Attribute::Class, EntryClass::ExtensibleObject.to_value()),
2879 (
2880 Attribute::Uuid,
2881 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2882 ),
2883 (Attribute::MultiValue, Value::Utf8("zzzz".to_string()))
2884 )
2885 .into_invalid_new();
2886
2887 assert_eq!(
2888 e_extensible_bad.validate(&schema),
2889 Err(SchemaError::InvalidAttributeSyntax(
2890 "multivalue".to_string()
2891 ))
2892 );
2893
2894 let e_extensible_phantom = entry_init!(
2896 (Attribute::Class, EntryClass::ExtensibleObject.to_value()),
2897 (
2898 Attribute::Uuid,
2899 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2900 ),
2901 (Attribute::PasswordImport, Value::Utf8("zzzz".to_string()))
2902 )
2903 .into_invalid_new();
2904
2905 assert_eq!(
2906 e_extensible_phantom.validate(&schema),
2907 Err(SchemaError::PhantomAttribute(
2908 Attribute::PasswordImport.to_string()
2909 ))
2910 );
2911
2912 let e_extensible = entry_init!(
2913 (Attribute::Class, EntryClass::ExtensibleObject.to_value()),
2914 (
2915 Attribute::Uuid,
2916 Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
2917 ),
2918 (Attribute::MultiValue, Value::Bool(true))
2919 )
2920 .into_invalid_new();
2921
2922 assert!(e_extensible.validate(&schema).is_ok());
2924 }
2925
2926 #[test]
2927 fn test_schema_filter_validation() {
2928 let schema_outer = Schema::new().expect("failed to create schema");
2929 let schema = schema_outer.read();
2930
2931 let f_bool = filter_all!(f_eq(Attribute::MultiValue, PartialValue::new_iutf8("zzzz")));
2933 assert_eq!(
2934 f_bool.validate(&schema),
2935 Err(SchemaError::InvalidAttributeSyntax(
2936 "multivalue".to_string()
2937 ))
2938 );
2939 let f_insense = filter_all!(f_eq(Attribute::Class, EntryClass::AttributeType.into()));
2941 assert_eq!(
2942 f_insense.validate(&schema),
2943 Ok(filter_valid!(f_eq(
2944 Attribute::Class,
2945 EntryClass::AttributeType.into()
2946 )))
2947 );
2948 let f_or_empty = filter_all!(f_or!([]));
2950 assert_eq!(f_or_empty.validate(&schema), Err(SchemaError::EmptyFilter));
2951 let f_or = filter_all!(f_or!([f_eq(
2952 Attribute::MultiValue,
2953 PartialValue::new_iutf8("zzzz")
2954 )]));
2955 assert_eq!(
2956 f_or.validate(&schema),
2957 Err(SchemaError::InvalidAttributeSyntax(
2958 "multivalue".to_string()
2959 ))
2960 );
2961 let f_or_mult = filter_all!(f_and!([
2962 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
2963 f_eq(Attribute::MultiValue, PartialValue::new_iutf8("zzzzzzz")),
2964 ]));
2965 assert_eq!(
2966 f_or_mult.validate(&schema),
2967 Err(SchemaError::InvalidAttributeSyntax(
2968 "multivalue".to_string()
2969 ))
2970 );
2971 let f_or_ok = filter_all!(f_andnot(f_and!([
2973 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
2974 f_sub(Attribute::Class, EntryClass::ClassType.into()),
2975 f_pres(Attribute::Class)
2976 ])));
2977 assert_eq!(
2978 f_or_ok.validate(&schema),
2979 Ok(filter_valid!(f_andnot(f_and!([
2980 f_eq(Attribute::Class, EntryClass::AttributeType.into()),
2981 f_sub(Attribute::Class, EntryClass::ClassType.into()),
2982 f_pres(Attribute::Class)
2983 ]))))
2984 );
2985 }
2986
2987 #[test]
2988 fn test_schema_class_phantom_reject() {
2989 let schema_outer = Schema::new().expect("failed to create schema");
2991 let mut schema = schema_outer.write_blocking();
2992
2993 assert!(schema.validate().is_empty());
2994
2995 let class = SchemaClass {
2997 name: AttrString::from("testobject"),
2998 uuid: Uuid::new_v4(),
2999 description: String::from("test object"),
3000 systemmay: vec![Attribute::Claim],
3001 ..Default::default()
3002 };
3003
3004 assert!(schema.update_classes(vec![class]).is_ok());
3005
3006 assert_eq!(schema.validate().len(), 1);
3007 }
3008
3009 #[test]
3010 fn test_schema_class_exclusion_requires() {
3011 sketching::test_init();
3012
3013 let schema_outer = Schema::new().expect("failed to create schema");
3014 let mut schema = schema_outer.write_blocking();
3015
3016 assert!(schema.validate().is_empty());
3017
3018 let class_account = SchemaClass {
3021 name: Attribute::Account.into(),
3022 uuid: Uuid::new_v4(),
3023 description: String::from("account object"),
3024 systemmust: vec![
3025 Attribute::Class,
3026 Attribute::Uuid,
3027 Attribute::LastModifiedCid,
3028 Attribute::CreatedAtCid,
3029 ],
3030 systemsupplements: vec![EntryClass::Service.into(), EntryClass::Person.into()],
3031 ..Default::default()
3032 };
3033
3034 let class_person = SchemaClass {
3035 name: EntryClass::Person.into(),
3036 uuid: Uuid::new_v4(),
3037 description: String::from("person object"),
3038 systemmust: vec![
3039 Attribute::Class,
3040 Attribute::Uuid,
3041 Attribute::LastModifiedCid,
3042 Attribute::CreatedAtCid,
3043 ],
3044 ..Default::default()
3045 };
3046
3047 let class_service = SchemaClass {
3048 name: EntryClass::Service.into(),
3049 uuid: Uuid::new_v4(),
3050 description: String::from("service object"),
3051 systemmust: vec![
3052 Attribute::Class,
3053 Attribute::Uuid,
3054 Attribute::LastModifiedCid,
3055 Attribute::CreatedAtCid,
3056 ],
3057 excludes: vec![EntryClass::Person.into()],
3058 ..Default::default()
3059 };
3060
3061 assert!(schema
3062 .update_classes(vec![class_account, class_person, class_service])
3063 .is_ok());
3064
3065 let e_account = entry_init!(
3067 (Attribute::Class, EntryClass::Account.to_value()),
3068 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3069 )
3070 .into_invalid_new();
3071
3072 assert_eq!(
3073 e_account.validate(&schema),
3074 Err(SchemaError::SupplementsNotSatisfied(vec![
3075 EntryClass::Service.into(),
3076 EntryClass::Person.into(),
3077 ]))
3078 );
3079
3080 let e_service_person = entry_init!(
3095 (Attribute::Class, EntryClass::Service.to_value()),
3096 (Attribute::Class, EntryClass::Account.to_value()),
3097 (Attribute::Class, EntryClass::Person.to_value()),
3098 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3099 )
3100 .into_invalid_new();
3101
3102 assert_eq!(
3103 e_service_person.validate(&schema),
3104 Err(SchemaError::ExcludesNotSatisfied(vec![
3105 EntryClass::Person.to_string()
3106 ]))
3107 );
3108
3109 let e_service_valid = entry_init!(
3111 (Attribute::Class, EntryClass::Service.to_value()),
3112 (Attribute::Class, EntryClass::Account.to_value()),
3113 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3114 )
3115 .into_invalid_new();
3116
3117 assert!(e_service_valid.validate(&schema).is_ok());
3118
3119 let e_person_valid = entry_init!(
3120 (Attribute::Class, EntryClass::Person.to_value()),
3121 (Attribute::Class, EntryClass::Account.to_value()),
3122 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3123 )
3124 .into_invalid_new();
3125
3126 assert!(e_person_valid.validate(&schema).is_ok());
3127
3128 let e_person_valid = entry_init!(
3129 (Attribute::Class, EntryClass::Person.to_value()),
3130 (Attribute::Uuid, Value::Uuid(Uuid::new_v4()))
3131 )
3132 .into_invalid_new();
3133
3134 assert!(e_person_valid.validate(&schema).is_ok());
3135 }
3136}