mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Implement attribute uniqueness. (#82)
Implements #72, attribute uniqueness. This extends schema to have a field "unique" which means a value should be unique for that object, and all other live objects (recycle and tombstones excluded). Note UUID has to retain special handling in base.rs and can't usethis due to needing to check with recycled too..
This commit is contained in:
parent
b4fc71b27d
commit
d436291eff
|
@ -65,6 +65,7 @@ pub enum ConsistencyError {
|
||||||
RefintNotUpheld(u64),
|
RefintNotUpheld(u64),
|
||||||
MemberOfInvalid(u64),
|
MemberOfInvalid(u64),
|
||||||
InvalidAttributeType(&'static str),
|
InvalidAttributeType(&'static str),
|
||||||
|
DuplicateUniqueAttribute(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== higher level types ===== */
|
/* ===== higher level types ===== */
|
||||||
|
|
|
@ -489,7 +489,9 @@ pub trait AccessControlsTransaction {
|
||||||
// true -> entry is allowed in result set
|
// true -> entry is allowed in result set
|
||||||
// false -> the entry is not allowed to be searched by this entity, so is
|
// false -> the entry is not allowed to be searched by this entity, so is
|
||||||
// excluded.
|
// excluded.
|
||||||
requested_attrs.is_subset(&allowed_attrs)
|
let decision = requested_attrs.is_subset(&allowed_attrs);
|
||||||
|
audit_log!(audit, "search attr decision --> {:?}", decision);
|
||||||
|
decision
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
|
@ -148,9 +148,12 @@ pub static JSON_ANONYMOUS_V1: &'static str = r#"{
|
||||||
pub static UUID_SCHEMA_ATTR_CLASS: &'static str = "00000000-0000-0000-0000-ffff00000000";
|
pub static UUID_SCHEMA_ATTR_CLASS: &'static str = "00000000-0000-0000-0000-ffff00000000";
|
||||||
pub static UUID_SCHEMA_ATTR_UUID: &'static str = "00000000-0000-0000-0000-ffff00000001";
|
pub static UUID_SCHEMA_ATTR_UUID: &'static str = "00000000-0000-0000-0000-ffff00000001";
|
||||||
pub static UUID_SCHEMA_ATTR_NAME: &'static str = "00000000-0000-0000-0000-ffff00000002";
|
pub static UUID_SCHEMA_ATTR_NAME: &'static str = "00000000-0000-0000-0000-ffff00000002";
|
||||||
|
pub static UUID_SCHEMA_ATTR_ATTRIBUTENAME: &'static str = "00000000-0000-0000-0000-ffff00000048";
|
||||||
|
pub static UUID_SCHEMA_ATTR_CLASSNAME: &'static str = "00000000-0000-0000-0000-ffff00000049";
|
||||||
pub static UUID_SCHEMA_ATTR_PRINCIPAL_NAME: &'static str = "00000000-0000-0000-0000-ffff00000003";
|
pub static UUID_SCHEMA_ATTR_PRINCIPAL_NAME: &'static str = "00000000-0000-0000-0000-ffff00000003";
|
||||||
pub static UUID_SCHEMA_ATTR_DESCRIPTION: &'static str = "00000000-0000-0000-0000-ffff00000004";
|
pub static UUID_SCHEMA_ATTR_DESCRIPTION: &'static str = "00000000-0000-0000-0000-ffff00000004";
|
||||||
pub static UUID_SCHEMA_ATTR_MULTIVALUE: &'static str = "00000000-0000-0000-0000-ffff00000005";
|
pub static UUID_SCHEMA_ATTR_MULTIVALUE: &'static str = "00000000-0000-0000-0000-ffff00000005";
|
||||||
|
pub static UUID_SCHEMA_ATTR_UNIQUE: &'static str = "00000000-0000-0000-0000-ffff00000047";
|
||||||
pub static UUID_SCHEMA_ATTR_INDEX: &'static str = "00000000-0000-0000-0000-ffff00000006";
|
pub static UUID_SCHEMA_ATTR_INDEX: &'static str = "00000000-0000-0000-0000-ffff00000006";
|
||||||
pub static UUID_SCHEMA_ATTR_SYNTAX: &'static str = "00000000-0000-0000-0000-ffff00000007";
|
pub static UUID_SCHEMA_ATTR_SYNTAX: &'static str = "00000000-0000-0000-0000-ffff00000007";
|
||||||
pub static UUID_SCHEMA_ATTR_SYSTEMMAY: &'static str = "00000000-0000-0000-0000-ffff00000008";
|
pub static UUID_SCHEMA_ATTR_SYSTEMMAY: &'static str = "00000000-0000-0000-0000-ffff00000008";
|
||||||
|
@ -215,10 +218,13 @@ pub static JSON_SCHEMA_ATTR_DISPLAYNAME: &'static str = r#"{
|
||||||
"index": [
|
"index": [
|
||||||
"EQUALITY"
|
"EQUALITY"
|
||||||
],
|
],
|
||||||
|
"unique": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
"multivalue": [
|
"multivalue": [
|
||||||
"false"
|
"false"
|
||||||
],
|
],
|
||||||
"name": [
|
"attributename": [
|
||||||
"displayname"
|
"displayname"
|
||||||
],
|
],
|
||||||
"syntax": [
|
"syntax": [
|
||||||
|
@ -248,10 +254,13 @@ pub static JSON_SCHEMA_ATTR_MAIL: &'static str = r#"
|
||||||
"index": [
|
"index": [
|
||||||
"EQUALITY"
|
"EQUALITY"
|
||||||
],
|
],
|
||||||
|
"unique": [
|
||||||
|
"true"
|
||||||
|
],
|
||||||
"multivalue": [
|
"multivalue": [
|
||||||
"true"
|
"true"
|
||||||
],
|
],
|
||||||
"name": [
|
"attributename": [
|
||||||
"mail"
|
"mail"
|
||||||
],
|
],
|
||||||
"syntax": [
|
"syntax": [
|
||||||
|
@ -280,10 +289,13 @@ pub static JSON_SCHEMA_ATTR_SSH_PUBLICKEY: &'static str = r#"
|
||||||
"SSH public keys of the object"
|
"SSH public keys of the object"
|
||||||
],
|
],
|
||||||
"index": [],
|
"index": [],
|
||||||
|
"unique": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
"multivalue": [
|
"multivalue": [
|
||||||
"true"
|
"true"
|
||||||
],
|
],
|
||||||
"name": [
|
"attributename": [
|
||||||
"ssh_publickey"
|
"ssh_publickey"
|
||||||
],
|
],
|
||||||
"syntax": [
|
"syntax": [
|
||||||
|
@ -313,10 +325,13 @@ pub static JSON_SCHEMA_ATTR_PRIMARY_CREDENTIAL: &'static str = r#"
|
||||||
"Primary credential material of the account for authentication interactively."
|
"Primary credential material of the account for authentication interactively."
|
||||||
],
|
],
|
||||||
"index": [],
|
"index": [],
|
||||||
|
"unique": [
|
||||||
|
"false"
|
||||||
|
],
|
||||||
"multivalue": [
|
"multivalue": [
|
||||||
"false"
|
"false"
|
||||||
],
|
],
|
||||||
"name": [
|
"attributename": [
|
||||||
"primary_credential"
|
"primary_credential"
|
||||||
],
|
],
|
||||||
"syntax": [
|
"syntax": [
|
||||||
|
@ -345,7 +360,7 @@ pub static JSON_SCHEMA_CLASS_PERSON: &'static str = r#"
|
||||||
"description": [
|
"description": [
|
||||||
"Object representation of a person"
|
"Object representation of a person"
|
||||||
],
|
],
|
||||||
"name": [
|
"classname": [
|
||||||
"person"
|
"person"
|
||||||
],
|
],
|
||||||
"systemmay": [
|
"systemmay": [
|
||||||
|
@ -379,7 +394,7 @@ pub static JSON_SCHEMA_CLASS_GROUP: &'static str = r#"
|
||||||
"description": [
|
"description": [
|
||||||
"Object representation of a group"
|
"Object representation of a group"
|
||||||
],
|
],
|
||||||
"name": [
|
"classname": [
|
||||||
"group"
|
"group"
|
||||||
],
|
],
|
||||||
"systemmay": [
|
"systemmay": [
|
||||||
|
@ -410,7 +425,7 @@ pub static JSON_SCHEMA_CLASS_ACCOUNT: &'static str = r#"
|
||||||
"description": [
|
"description": [
|
||||||
"Object representation of a person"
|
"Object representation of a person"
|
||||||
],
|
],
|
||||||
"name": [
|
"classname": [
|
||||||
"account"
|
"account"
|
||||||
],
|
],
|
||||||
"systemmay": [
|
"systemmay": [
|
||||||
|
|
|
@ -251,7 +251,7 @@ impl Entry<EntryInvalid, EntryNew> {
|
||||||
.map(|(k, vs)| {
|
.map(|(k, vs)| {
|
||||||
let attr = k.to_lowercase();
|
let attr = k.to_lowercase();
|
||||||
let vv: BTreeSet<Value> = match attr.as_str() {
|
let vv: BTreeSet<Value> = match attr.as_str() {
|
||||||
"name" | "version" | "domain" => {
|
"name" | "attributename" | "classname" | "version" | "domain" => {
|
||||||
vs.into_iter().map(|v| Value::new_iutf8(v)).collect()
|
vs.into_iter().map(|v| Value::new_iutf8(v)).collect()
|
||||||
}
|
}
|
||||||
"userid" | "uidnumber" => {
|
"userid" | "uidnumber" => {
|
||||||
|
@ -277,7 +277,7 @@ impl Entry<EntryInvalid, EntryNew> {
|
||||||
"member" | "memberof" | "directmemberof" => {
|
"member" | "memberof" | "directmemberof" => {
|
||||||
vs.into_iter().map(|v| Value::new_refer_s(v.as_str()).unwrap() ).collect()
|
vs.into_iter().map(|v| Value::new_refer_s(v.as_str()).unwrap() ).collect()
|
||||||
}
|
}
|
||||||
"acp_enable" | "multivalue" => {
|
"acp_enable" | "multivalue" | "unique" => {
|
||||||
vs.into_iter().map(|v| Value::new_bools(v.as_str())
|
vs.into_iter().map(|v| Value::new_bools(v.as_str())
|
||||||
.unwrap_or_else(|| {
|
.unwrap_or_else(|| {
|
||||||
warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string");
|
warn!("WARNING: Allowing syntax incorrect attribute to be presented UTF8 string");
|
||||||
|
@ -1298,6 +1298,7 @@ impl From<&SchemaAttribute> for Entry<EntryValid, EntryNew> {
|
||||||
let desc_v = btreeset![Value::new_utf8(s.description.clone())];
|
let desc_v = btreeset![Value::new_utf8(s.description.clone())];
|
||||||
|
|
||||||
let multivalue_v = btreeset![Value::from(s.multivalue)];
|
let multivalue_v = btreeset![Value::from(s.multivalue)];
|
||||||
|
let unique_v = btreeset![Value::from(s.unique)];
|
||||||
|
|
||||||
let index_v: BTreeSet<_> = s.index.iter().map(|i| Value::from(i.clone())).collect();
|
let index_v: BTreeSet<_> = s.index.iter().map(|i| Value::from(i.clone())).collect();
|
||||||
|
|
||||||
|
@ -1305,10 +1306,11 @@ impl From<&SchemaAttribute> for Entry<EntryValid, EntryNew> {
|
||||||
|
|
||||||
// Build the BTreeMap of the attributes relevant
|
// Build the BTreeMap of the attributes relevant
|
||||||
let mut attrs: BTreeMap<String, BTreeSet<Value>> = BTreeMap::new();
|
let mut attrs: BTreeMap<String, BTreeSet<Value>> = BTreeMap::new();
|
||||||
attrs.insert("name".to_string(), name_v);
|
attrs.insert("attributename".to_string(), name_v);
|
||||||
attrs.insert("description".to_string(), desc_v);
|
attrs.insert("description".to_string(), desc_v);
|
||||||
attrs.insert("uuid".to_string(), uuid_v);
|
attrs.insert("uuid".to_string(), uuid_v);
|
||||||
attrs.insert("multivalue".to_string(), multivalue_v);
|
attrs.insert("multivalue".to_string(), multivalue_v);
|
||||||
|
attrs.insert("unique".to_string(), unique_v);
|
||||||
attrs.insert("index".to_string(), index_v);
|
attrs.insert("index".to_string(), index_v);
|
||||||
attrs.insert("syntax".to_string(), syntax_v);
|
attrs.insert("syntax".to_string(), syntax_v);
|
||||||
attrs.insert(
|
attrs.insert(
|
||||||
|
@ -1339,7 +1341,7 @@ impl From<&SchemaClass> for Entry<EntryValid, EntryNew> {
|
||||||
let desc_v = btreeset![Value::new_utf8(s.description.clone())];
|
let desc_v = btreeset![Value::new_utf8(s.description.clone())];
|
||||||
|
|
||||||
let mut attrs: BTreeMap<String, BTreeSet<Value>> = BTreeMap::new();
|
let mut attrs: BTreeMap<String, BTreeSet<Value>> = BTreeMap::new();
|
||||||
attrs.insert("name".to_string(), name_v);
|
attrs.insert("classname".to_string(), name_v);
|
||||||
attrs.insert("description".to_string(), desc_v);
|
attrs.insert("description".to_string(), desc_v);
|
||||||
attrs.insert("uuid".to_string(), uuid_v);
|
attrs.insert("uuid".to_string(), uuid_v);
|
||||||
attrs.insert(
|
attrs.insert(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![deny(warnings)]
|
// #![deny(warnings)]
|
||||||
#![warn(unused_extern_crates)]
|
#![warn(unused_extern_crates)]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
357
rsidmd/src/lib/plugins/attrunique.rs
Normal file
357
rsidmd/src/lib/plugins/attrunique.rs
Normal file
|
@ -0,0 +1,357 @@
|
||||||
|
// Attribute uniqueness plugin. We read the schema and determine if the
|
||||||
|
// value should be unique, and how to handle if it is not. This will
|
||||||
|
// matter a lot when it comes to replication based on first-wins or
|
||||||
|
// both change approaches.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
use crate::audit::AuditScope;
|
||||||
|
use crate::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew};
|
||||||
|
use crate::event::{CreateEvent, ModifyEvent};
|
||||||
|
use crate::plugins::Plugin;
|
||||||
|
use crate::schema::SchemaTransaction;
|
||||||
|
use crate::server::{
|
||||||
|
QueryServerReadTransaction, QueryServerTransaction, QueryServerWriteTransaction,
|
||||||
|
};
|
||||||
|
use crate::value::PartialValue;
|
||||||
|
use rsidm_proto::v1::{ConsistencyError, OperationError};
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
pub struct AttrUnique;
|
||||||
|
|
||||||
|
fn get_cand_attr_set<VALID, STATE>(
|
||||||
|
au: &mut AuditScope,
|
||||||
|
cand: &Vec<Entry<VALID, STATE>>,
|
||||||
|
attr: &str,
|
||||||
|
) -> Result<BTreeMap<PartialValue, PartialValue>, OperationError> {
|
||||||
|
let mut cand_attr: BTreeMap<PartialValue, PartialValue> = BTreeMap::new();
|
||||||
|
|
||||||
|
for e in cand.iter() {
|
||||||
|
let uuid = match e.get_ava_single("uuid") {
|
||||||
|
Some(v) => v.to_partialvalue(),
|
||||||
|
None => {
|
||||||
|
return Err(OperationError::InvalidEntryState);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Get the value and uuid
|
||||||
|
//for each value in the ava.
|
||||||
|
let mut values: Vec<PartialValue> = match e.get_ava(attr) {
|
||||||
|
Some(vs) => {
|
||||||
|
// We have values, map them.
|
||||||
|
vs.into_iter().map(|v| v.to_partialvalue()).collect()
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
// No values, so empty set.
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
for v in values.drain(..) {
|
||||||
|
match cand_attr.insert(v, uuid.clone()) {
|
||||||
|
// Didn't exist, move on.
|
||||||
|
None => {}
|
||||||
|
// The duplicate/rejected value moved out of the tree
|
||||||
|
Some(vr) => {
|
||||||
|
audit_log!(
|
||||||
|
au,
|
||||||
|
"ava already exists -> {:?}: {:?} on {:?}",
|
||||||
|
attr,
|
||||||
|
vr,
|
||||||
|
uuid
|
||||||
|
);
|
||||||
|
return Err(OperationError::Plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(cand_attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_unique<STATE>(
|
||||||
|
au: &mut AuditScope,
|
||||||
|
qs: &mut QueryServerWriteTransaction,
|
||||||
|
cand: &Vec<Entry<EntryInvalid, STATE>>,
|
||||||
|
attr: &str,
|
||||||
|
) -> Result<(), OperationError> {
|
||||||
|
debug!("{:?}", attr);
|
||||||
|
|
||||||
|
// Build a set of all the value -> uuid for the cands.
|
||||||
|
// If already exist, reject due to dup.
|
||||||
|
let cand_attr = try_audit!(au, get_cand_attr_set(au, cand, attr));
|
||||||
|
|
||||||
|
debug!("{:?}", cand_attr);
|
||||||
|
|
||||||
|
// No candidates to check!
|
||||||
|
if cand_attr.len() == 0 {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now do an internal search on name and !uuid for each
|
||||||
|
|
||||||
|
// Or
|
||||||
|
let filt_in = filter!(f_or(
|
||||||
|
// for each cand_attr
|
||||||
|
cand_attr
|
||||||
|
.into_iter()
|
||||||
|
.map(|(v, uuid)| {
|
||||||
|
// and[ attr eq k, andnot [ uuid eq v ]]
|
||||||
|
// Basically this says where name but also not self.
|
||||||
|
f_and(vec![FC::Eq(attr, v), f_andnot(FC::Eq("uuid", uuid))])
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
));
|
||||||
|
|
||||||
|
debug!("{:?}", filt_in);
|
||||||
|
|
||||||
|
// If any results, reject.
|
||||||
|
let conflict_cand = try_audit!(au, qs.internal_search(au, filt_in));
|
||||||
|
|
||||||
|
// If all okay, okay!
|
||||||
|
if conflict_cand.len() > 0 {
|
||||||
|
return Err(OperationError::Plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for AttrUnique {
|
||||||
|
fn id() -> &'static str {
|
||||||
|
"plugin_attrunique"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pre_create_transform(
|
||||||
|
au: &mut AuditScope,
|
||||||
|
qs: &mut QueryServerWriteTransaction,
|
||||||
|
cand: &mut Vec<Entry<EntryInvalid, EntryNew>>,
|
||||||
|
_ce: &CreateEvent,
|
||||||
|
) -> Result<(), OperationError> {
|
||||||
|
// Needs to clone to avoid a borrow issue?
|
||||||
|
let uniqueattrs = {
|
||||||
|
let schema = qs.get_schema();
|
||||||
|
schema.get_attributes_unique()
|
||||||
|
};
|
||||||
|
|
||||||
|
let r: Result<(), OperationError> = uniqueattrs
|
||||||
|
.iter()
|
||||||
|
.map(|attr| enforce_unique(au, qs, cand, attr.as_str()))
|
||||||
|
.collect();
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pre_modify(
|
||||||
|
au: &mut AuditScope,
|
||||||
|
qs: &mut QueryServerWriteTransaction,
|
||||||
|
cand: &mut Vec<Entry<EntryInvalid, EntryCommitted>>,
|
||||||
|
_me: &ModifyEvent,
|
||||||
|
) -> Result<(), OperationError> {
|
||||||
|
// Needs to clone to avoid a borrow issue?
|
||||||
|
let uniqueattrs = {
|
||||||
|
let schema = qs.get_schema();
|
||||||
|
schema.get_attributes_unique()
|
||||||
|
};
|
||||||
|
|
||||||
|
let r: Result<(), OperationError> = uniqueattrs
|
||||||
|
.iter()
|
||||||
|
.map(|attr| enforce_unique(au, qs, cand, attr.as_str()))
|
||||||
|
.collect();
|
||||||
|
r
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify(
|
||||||
|
au: &mut AuditScope,
|
||||||
|
qs: &QueryServerReadTransaction,
|
||||||
|
) -> Vec<Result<(), ConsistencyError>> {
|
||||||
|
// Only check live entries, not recycled.
|
||||||
|
let filt_in = filter!(f_pres("class"));
|
||||||
|
|
||||||
|
let all_cand = match qs
|
||||||
|
.internal_search(au, filt_in)
|
||||||
|
.map_err(|_| Err(ConsistencyError::QueryServerSearchFailure))
|
||||||
|
{
|
||||||
|
Ok(all_cand) => all_cand,
|
||||||
|
Err(e) => return vec![e],
|
||||||
|
};
|
||||||
|
|
||||||
|
let uniqueattrs = {
|
||||||
|
let schema = qs.get_schema();
|
||||||
|
schema.get_attributes_unique()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut res: Vec<Result<(), ConsistencyError>> = Vec::new();
|
||||||
|
|
||||||
|
for attr in uniqueattrs.iter() {
|
||||||
|
// We do a fully in memory check.
|
||||||
|
if get_cand_attr_set(au, &all_cand, attr.as_str()).is_err() {
|
||||||
|
res.push(Err(ConsistencyError::DuplicateUniqueAttribute(
|
||||||
|
attr.clone(),
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!("{:?}", res);
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::entry::{Entry, EntryInvalid, EntryNew};
|
||||||
|
use crate::modify::{Modify, ModifyList};
|
||||||
|
use crate::value::{PartialValue, Value};
|
||||||
|
use rsidm_proto::v1::OperationError;
|
||||||
|
// Test entry in db, and same name, reject.
|
||||||
|
#[test]
|
||||||
|
fn test_pre_create_name_unique() {
|
||||||
|
let e: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||||
|
r#"{
|
||||||
|
"valid": null,
|
||||||
|
"state": null,
|
||||||
|
"attrs": {
|
||||||
|
"class": ["person"],
|
||||||
|
"name": ["testperson"],
|
||||||
|
"description": ["testperson"],
|
||||||
|
"displayname": ["testperson"]
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let create = vec![e.clone()];
|
||||||
|
let preload = vec![e];
|
||||||
|
|
||||||
|
run_create_test!(
|
||||||
|
Err(OperationError::Plugin),
|
||||||
|
preload,
|
||||||
|
create,
|
||||||
|
None,
|
||||||
|
|_, _| {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test two entries in create that would have same name, reject.
|
||||||
|
#[test]
|
||||||
|
fn test_pre_create_name_unique_2() {
|
||||||
|
let e: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||||
|
r#"{
|
||||||
|
"valid": null,
|
||||||
|
"state": null,
|
||||||
|
"attrs": {
|
||||||
|
"class": ["person"],
|
||||||
|
"name": ["testperson"],
|
||||||
|
"description": ["testperson"],
|
||||||
|
"displayname": ["testperson"]
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let create = vec![e.clone(), e];
|
||||||
|
let preload = Vec::new();
|
||||||
|
|
||||||
|
run_create_test!(
|
||||||
|
Err(OperationError::Plugin),
|
||||||
|
preload,
|
||||||
|
create,
|
||||||
|
None,
|
||||||
|
|_, _| {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember, an entry can't have a duplicate value within itself so we don't need to
|
||||||
|
// test this case.
|
||||||
|
|
||||||
|
// A mod to something that exists, reject.
|
||||||
|
#[test]
|
||||||
|
fn test_pre_modify_name_unique() {
|
||||||
|
let ea: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||||
|
r#"{
|
||||||
|
"valid": null,
|
||||||
|
"state": null,
|
||||||
|
"attrs": {
|
||||||
|
"class": ["group"],
|
||||||
|
"name": ["testgroup_a"],
|
||||||
|
"description": ["testgroup"]
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let eb: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||||
|
r#"{
|
||||||
|
"valid": null,
|
||||||
|
"state": null,
|
||||||
|
"attrs": {
|
||||||
|
"class": ["group"],
|
||||||
|
"name": ["testgroup_b"],
|
||||||
|
"description": ["testgroup"]
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let preload = vec![ea, eb];
|
||||||
|
|
||||||
|
run_modify_test!(
|
||||||
|
Err(OperationError::Plugin),
|
||||||
|
preload,
|
||||||
|
filter!(f_or!([f_eq(
|
||||||
|
"name",
|
||||||
|
PartialValue::new_iutf8s("testgroup_b")
|
||||||
|
),])),
|
||||||
|
ModifyList::new_list(vec![
|
||||||
|
Modify::Purged("name".to_string()),
|
||||||
|
Modify::Present("name".to_string(), Value::new_iutf8s("testgroup_a"))
|
||||||
|
]),
|
||||||
|
None,
|
||||||
|
|_, _| {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two items modded to have the same value, reject.
|
||||||
|
#[test]
|
||||||
|
fn test_pre_modify_name_unique_2() {
|
||||||
|
let ea: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||||
|
r#"{
|
||||||
|
"valid": null,
|
||||||
|
"state": null,
|
||||||
|
"attrs": {
|
||||||
|
"class": ["group"],
|
||||||
|
"name": ["testgroup_a"],
|
||||||
|
"description": ["testgroup"]
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let eb: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||||
|
r#"{
|
||||||
|
"valid": null,
|
||||||
|
"state": null,
|
||||||
|
"attrs": {
|
||||||
|
"class": ["group"],
|
||||||
|
"name": ["testgroup_b"],
|
||||||
|
"description": ["testgroup"]
|
||||||
|
}
|
||||||
|
}"#,
|
||||||
|
);
|
||||||
|
|
||||||
|
let preload = vec![ea, eb];
|
||||||
|
|
||||||
|
run_modify_test!(
|
||||||
|
Err(OperationError::Plugin),
|
||||||
|
preload,
|
||||||
|
filter!(f_or!([
|
||||||
|
f_eq("name", PartialValue::new_iutf8s("testgroup_a")),
|
||||||
|
f_eq("name", PartialValue::new_iutf8s("testgroup_b")),
|
||||||
|
])),
|
||||||
|
ModifyList::new_list(vec![
|
||||||
|
Modify::Purged("name".to_string()),
|
||||||
|
Modify::Present("name".to_string(), Value::new_iutf8s("testgroup"))
|
||||||
|
]),
|
||||||
|
None,
|
||||||
|
|_, _| {}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_verify_name_unique() {
|
||||||
|
// Can we preload two dups and verify to show we detect?
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ use rsidm_proto::v1::{ConsistencyError, OperationError};
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
mod macros;
|
mod macros;
|
||||||
|
|
||||||
|
mod attrunique;
|
||||||
mod base;
|
mod base;
|
||||||
mod failure;
|
mod failure;
|
||||||
mod memberof;
|
mod memberof;
|
||||||
|
@ -277,7 +278,10 @@ impl Plugins {
|
||||||
ce: &CreateEvent,
|
ce: &CreateEvent,
|
||||||
) -> Result<(), OperationError> {
|
) -> Result<(), OperationError> {
|
||||||
audit_segment!(au, || {
|
audit_segment!(au, || {
|
||||||
let res = run_pre_create_transform_plugin!(au, qs, cand, ce, base::Base);
|
let res =
|
||||||
|
run_pre_create_transform_plugin!(au, qs, cand, ce, base::Base).and_then(|_| {
|
||||||
|
run_pre_create_transform_plugin!(au, qs, cand, ce, attrunique::AttrUnique)
|
||||||
|
});
|
||||||
|
|
||||||
res
|
res
|
||||||
})
|
})
|
||||||
|
@ -318,7 +322,8 @@ impl Plugins {
|
||||||
) -> Result<(), OperationError> {
|
) -> Result<(), OperationError> {
|
||||||
audit_segment!(au, || {
|
audit_segment!(au, || {
|
||||||
let res = run_pre_modify_plugin!(au, qs, cand, me, protected::Protected)
|
let res = run_pre_modify_plugin!(au, qs, cand, me, protected::Protected)
|
||||||
.and_then(|_| run_pre_modify_plugin!(au, qs, cand, me, base::Base));
|
.and_then(|_| run_pre_modify_plugin!(au, qs, cand, me, base::Base))
|
||||||
|
.and_then(|_| run_pre_modify_plugin!(au, qs, cand, me, attrunique::AttrUnique));
|
||||||
|
|
||||||
res
|
res
|
||||||
})
|
})
|
||||||
|
@ -374,6 +379,7 @@ impl Plugins {
|
||||||
) -> Vec<Result<(), ConsistencyError>> {
|
) -> Vec<Result<(), ConsistencyError>> {
|
||||||
let mut results = Vec::new();
|
let mut results = Vec::new();
|
||||||
run_verify_plugin!(au, qs, &mut results, base::Base);
|
run_verify_plugin!(au, qs, &mut results, base::Base);
|
||||||
|
run_verify_plugin!(au, qs, &mut results, attrunique::AttrUnique);
|
||||||
run_verify_plugin!(au, qs, &mut results, refint::ReferentialIntegrity);
|
run_verify_plugin!(au, qs, &mut results, refint::ReferentialIntegrity);
|
||||||
run_verify_plugin!(au, qs, &mut results, memberof::MemberOf);
|
run_verify_plugin!(au, qs, &mut results, memberof::MemberOf);
|
||||||
results
|
results
|
||||||
|
|
|
@ -184,7 +184,7 @@ mod tests {
|
||||||
"acp_targetscope": [
|
"acp_targetscope": [
|
||||||
"{\"Pres\":\"class\"}"
|
"{\"Pres\":\"class\"}"
|
||||||
],
|
],
|
||||||
"acp_search_attr": ["name", "class", "uuid"],
|
"acp_search_attr": ["name", "class", "uuid", "classname", "attributename"],
|
||||||
"acp_modify_class": ["system"],
|
"acp_modify_class": ["system"],
|
||||||
"acp_modify_removedattr": ["class", "displayname", "may", "must"],
|
"acp_modify_removedattr": ["class", "displayname", "may", "must"],
|
||||||
"acp_modify_presentattr": ["class", "displayname", "may", "must"],
|
"acp_modify_presentattr": ["class", "displayname", "may", "must"],
|
||||||
|
@ -295,7 +295,7 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "classtype"],
|
"class": ["object", "classtype"],
|
||||||
"name": ["testclass"],
|
"classname": ["testclass"],
|
||||||
"uuid": ["cfcae205-31c3-484b-8ced-667d1709c5e3"],
|
"uuid": ["cfcae205-31c3-484b-8ced-667d1709c5e3"],
|
||||||
"description": ["Test Class"]
|
"description": ["Test Class"]
|
||||||
}
|
}
|
||||||
|
@ -307,7 +307,7 @@ mod tests {
|
||||||
run_modify_test!(
|
run_modify_test!(
|
||||||
Ok(()),
|
Ok(()),
|
||||||
preload,
|
preload,
|
||||||
filter!(f_eq("name", PartialValue::new_iutf8s("testclass"))),
|
filter!(f_eq("classname", PartialValue::new_iutf8s("testclass"))),
|
||||||
modlist!([
|
modlist!([
|
||||||
m_pres("may", &Value::new_iutf8s("name")),
|
m_pres("may", &Value::new_iutf8s("name")),
|
||||||
m_pres("must", &Value::new_iutf8s("name")),
|
m_pres("must", &Value::new_iutf8s("name")),
|
||||||
|
|
|
@ -193,7 +193,7 @@ impl Plugin for ReferentialIntegrity {
|
||||||
) -> Vec<Result<(), ConsistencyError>> {
|
) -> Vec<Result<(), ConsistencyError>> {
|
||||||
// Get all entries as cand
|
// Get all entries as cand
|
||||||
// build a cand-uuid set
|
// build a cand-uuid set
|
||||||
let filt_in = filter!(f_pres("class"));
|
let filt_in = filter_all!(f_pres("class"));
|
||||||
|
|
||||||
let all_cand = match qs
|
let all_cand = match qs
|
||||||
.internal_search(au, filt_in)
|
.internal_search(au, filt_in)
|
||||||
|
|
|
@ -32,6 +32,7 @@ pub struct SchemaAttribute {
|
||||||
// Perhaps later add aliases?
|
// Perhaps later add aliases?
|
||||||
pub description: String,
|
pub description: String,
|
||||||
pub multivalue: bool,
|
pub multivalue: bool,
|
||||||
|
pub unique: bool,
|
||||||
pub index: Vec<IndexType>,
|
pub index: Vec<IndexType>,
|
||||||
pub syntax: SyntaxType,
|
pub syntax: SyntaxType,
|
||||||
}
|
}
|
||||||
|
@ -55,8 +56,8 @@ impl SchemaAttribute {
|
||||||
let name = try_audit!(
|
let name = try_audit!(
|
||||||
audit,
|
audit,
|
||||||
value
|
value
|
||||||
.get_ava_single_string("name")
|
.get_ava_single_string("attributename")
|
||||||
.ok_or(OperationError::InvalidSchemaState("missing name"))
|
.ok_or(OperationError::InvalidSchemaState("missing attributename"))
|
||||||
);
|
);
|
||||||
// description
|
// description
|
||||||
let description = try_audit!(
|
let description = try_audit!(
|
||||||
|
@ -73,6 +74,12 @@ impl SchemaAttribute {
|
||||||
.get_ava_single_bool("multivalue")
|
.get_ava_single_bool("multivalue")
|
||||||
.ok_or(OperationError::InvalidSchemaState("missing multivalue"))
|
.ok_or(OperationError::InvalidSchemaState("missing multivalue"))
|
||||||
);
|
);
|
||||||
|
let unique = try_audit!(
|
||||||
|
audit,
|
||||||
|
value
|
||||||
|
.get_ava_single_bool("unique")
|
||||||
|
.ok_or(OperationError::InvalidSchemaState("missing unique"))
|
||||||
|
);
|
||||||
// index vec
|
// index vec
|
||||||
// even if empty, it SHOULD be present ... (is that value to put an empty set?)
|
// even if empty, it SHOULD be present ... (is that value to put an empty set?)
|
||||||
// The get_ava_opt_index handles the optional case for us :)
|
// The get_ava_opt_index handles the optional case for us :)
|
||||||
|
@ -100,6 +107,7 @@ impl SchemaAttribute {
|
||||||
uuid: uuid,
|
uuid: uuid,
|
||||||
description: description,
|
description: description,
|
||||||
multivalue: multivalue,
|
multivalue: multivalue,
|
||||||
|
unique: unique,
|
||||||
index: index,
|
index: index,
|
||||||
syntax: syntax,
|
syntax: syntax,
|
||||||
})
|
})
|
||||||
|
@ -340,8 +348,8 @@ impl SchemaClass {
|
||||||
let name = try_audit!(
|
let name = try_audit!(
|
||||||
audit,
|
audit,
|
||||||
value
|
value
|
||||||
.get_ava_single_string("name")
|
.get_ava_single_string("classname")
|
||||||
.ok_or(OperationError::InvalidSchemaState("missing name"))
|
.ok_or(OperationError::InvalidSchemaState("missing classname"))
|
||||||
);
|
);
|
||||||
// description
|
// description
|
||||||
let description = try_audit!(
|
let description = try_audit!(
|
||||||
|
@ -408,6 +416,14 @@ pub trait SchemaTransaction {
|
||||||
an.to_lowercase()
|
an.to_lowercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_attributes_unique(&self) -> Vec<String> {
|
||||||
|
// This could be improved by caching this set on schema reload!
|
||||||
|
self.get_attributes()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(k, v)| if v.unique { Some(k.clone()) } else { None })
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
// Probably need something like get_classes or similar
|
// Probably need something like get_classes or similar
|
||||||
// so that externals can call and use this data.
|
// so that externals can call and use this data.
|
||||||
|
|
||||||
|
@ -449,6 +465,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("The set of classes defining an object"),
|
description: String::from("The set of classes defining an object"),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -461,6 +478,9 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("The universal unique id of the object"),
|
description: String::from("The universal unique id of the object"),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
// Uniqueness is handled by base.rs, not attrunique here due to
|
||||||
|
// needing to check recycled objects too.
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UUID,
|
syntax: SyntaxType::UUID,
|
||||||
},
|
},
|
||||||
|
@ -473,6 +493,33 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("The shortform name of an object"),
|
description: String::from("The shortform name of an object"),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: true,
|
||||||
|
index: vec![IndexType::EQUALITY],
|
||||||
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
s.attributes.insert(
|
||||||
|
String::from("attributename"),
|
||||||
|
SchemaAttribute {
|
||||||
|
name: String::from("attributename"),
|
||||||
|
uuid: Uuid::parse_str(UUID_SCHEMA_ATTR_ATTRIBUTENAME)
|
||||||
|
.expect("unable to parse static uuid"),
|
||||||
|
description: String::from("The name of a schema attribute"),
|
||||||
|
multivalue: false,
|
||||||
|
unique: true,
|
||||||
|
index: vec![IndexType::EQUALITY],
|
||||||
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
s.attributes.insert(
|
||||||
|
String::from("classname"),
|
||||||
|
SchemaAttribute {
|
||||||
|
name: String::from("classname"),
|
||||||
|
uuid: Uuid::parse_str(UUID_SCHEMA_ATTR_CLASSNAME)
|
||||||
|
.expect("unable to parse static uuid"),
|
||||||
|
description: String::from("The name of a schema class"),
|
||||||
|
multivalue: false,
|
||||||
|
unique: true,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -485,6 +532,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("A description of an attribute, object or class"),
|
description: String::from("A description of an attribute, object or class"),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![],
|
index: vec![],
|
||||||
syntax: SyntaxType::UTF8STRING,
|
syntax: SyntaxType::UTF8STRING,
|
||||||
},
|
},
|
||||||
|
@ -494,6 +542,16 @@ impl SchemaInner {
|
||||||
uuid: Uuid::parse_str(UUID_SCHEMA_ATTR_MULTIVALUE).expect("unable to parse static uuid"),
|
uuid: Uuid::parse_str(UUID_SCHEMA_ATTR_MULTIVALUE).expect("unable to parse static uuid"),
|
||||||
description: String::from("If true, this attribute is able to store multiple values rather than just a single value."),
|
description: String::from("If true, this attribute is able to store multiple values rather than just a single value."),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
|
index: vec![],
|
||||||
|
syntax: SyntaxType::BOOLEAN,
|
||||||
|
});
|
||||||
|
s.attributes.insert(String::from("unique"), SchemaAttribute {
|
||||||
|
name: String::from("unique"),
|
||||||
|
uuid: Uuid::parse_str(UUID_SCHEMA_ATTR_UNIQUE).expect("unable to parse static uuid"),
|
||||||
|
description: String::from("If true, this attribute must store a unique value through out the database."),
|
||||||
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
index: vec![],
|
index: vec![],
|
||||||
syntax: SyntaxType::BOOLEAN,
|
syntax: SyntaxType::BOOLEAN,
|
||||||
});
|
});
|
||||||
|
@ -507,6 +565,7 @@ impl SchemaInner {
|
||||||
"Describe the indexes to apply to instances of this attribute.",
|
"Describe the indexes to apply to instances of this attribute.",
|
||||||
),
|
),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![],
|
index: vec![],
|
||||||
syntax: SyntaxType::INDEX_ID,
|
syntax: SyntaxType::INDEX_ID,
|
||||||
},
|
},
|
||||||
|
@ -521,6 +580,7 @@ impl SchemaInner {
|
||||||
"Describe the syntax of this attribute. This affects indexing and sorting.",
|
"Describe the syntax of this attribute. This affects indexing and sorting.",
|
||||||
),
|
),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::SYNTAX_ID,
|
syntax: SyntaxType::SYNTAX_ID,
|
||||||
},
|
},
|
||||||
|
@ -535,6 +595,7 @@ impl SchemaInner {
|
||||||
"A list of system provided optional attributes this class can store.",
|
"A list of system provided optional attributes this class can store.",
|
||||||
),
|
),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![],
|
index: vec![],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -549,6 +610,7 @@ impl SchemaInner {
|
||||||
"A user modifiable list of optional attributes this class can store.",
|
"A user modifiable list of optional attributes this class can store.",
|
||||||
),
|
),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![],
|
index: vec![],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -563,6 +625,7 @@ impl SchemaInner {
|
||||||
"A list of system provided required attributes this class must store.",
|
"A list of system provided required attributes this class must store.",
|
||||||
),
|
),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![],
|
index: vec![],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -577,6 +640,7 @@ impl SchemaInner {
|
||||||
"A user modifiable list of required attributes this class must store.",
|
"A user modifiable list of required attributes this class must store.",
|
||||||
),
|
),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![],
|
index: vec![],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -591,6 +655,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("A flag to determine if this ACP is active for application. True is enabled, and enforce. False is checked but not enforced."),
|
description: String::from("A flag to determine if this ACP is active for application. True is enabled, and enforce. False is checked but not enforced."),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::BOOLEAN,
|
syntax: SyntaxType::BOOLEAN,
|
||||||
},
|
},
|
||||||
|
@ -606,6 +671,7 @@ impl SchemaInner {
|
||||||
"Who the ACP applies to, constraining or allowing operations.",
|
"Who the ACP applies to, constraining or allowing operations.",
|
||||||
),
|
),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY, IndexType::SUBSTRING],
|
index: vec![IndexType::EQUALITY, IndexType::SUBSTRING],
|
||||||
syntax: SyntaxType::JSON_FILTER,
|
syntax: SyntaxType::JSON_FILTER,
|
||||||
},
|
},
|
||||||
|
@ -620,6 +686,7 @@ impl SchemaInner {
|
||||||
"The effective targets of the ACP, IE what will be acted upon.",
|
"The effective targets of the ACP, IE what will be acted upon.",
|
||||||
),
|
),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY, IndexType::SUBSTRING],
|
index: vec![IndexType::EQUALITY, IndexType::SUBSTRING],
|
||||||
syntax: SyntaxType::JSON_FILTER,
|
syntax: SyntaxType::JSON_FILTER,
|
||||||
},
|
},
|
||||||
|
@ -632,6 +699,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("The attributes that may be viewed or searched by the reciever on targetscope."),
|
description: String::from("The attributes that may be viewed or searched by the reciever on targetscope."),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -646,6 +714,7 @@ impl SchemaInner {
|
||||||
"The set of classes that can be created on a new entry.",
|
"The set of classes that can be created on a new entry.",
|
||||||
),
|
),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -660,6 +729,7 @@ impl SchemaInner {
|
||||||
"The set of attribute types that can be created on an entry.",
|
"The set of attribute types that can be created on an entry.",
|
||||||
),
|
),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -673,6 +743,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("The set of attribute types that could be removed or purged in a modification."),
|
description: String::from("The set of attribute types that could be removed or purged in a modification."),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -685,6 +756,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("The set of attribute types that could be added or asserted in a modification."),
|
description: String::from("The set of attribute types that could be added or asserted in a modification."),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -697,6 +769,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
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."),
|
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."),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -710,6 +783,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("reverse group membership of the object"),
|
description: String::from("reverse group membership of the object"),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::REFERENCE_UUID,
|
syntax: SyntaxType::REFERENCE_UUID,
|
||||||
},
|
},
|
||||||
|
@ -722,6 +796,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("reverse direct group membership of the object"),
|
description: String::from("reverse direct group membership of the object"),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::REFERENCE_UUID,
|
syntax: SyntaxType::REFERENCE_UUID,
|
||||||
},
|
},
|
||||||
|
@ -734,6 +809,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("List of members of the group"),
|
description: String::from("List of members of the group"),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::REFERENCE_UUID,
|
syntax: SyntaxType::REFERENCE_UUID,
|
||||||
},
|
},
|
||||||
|
@ -749,6 +825,7 @@ impl SchemaInner {
|
||||||
"The systems internal migration version for provided objects",
|
"The systems internal migration version for provided objects",
|
||||||
),
|
),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -762,6 +839,7 @@ impl SchemaInner {
|
||||||
.expect("unable to parse static uuid"),
|
.expect("unable to parse static uuid"),
|
||||||
description: String::from("A DNS Domain name entry."),
|
description: String::from("A DNS Domain name entry."),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
},
|
},
|
||||||
|
@ -778,8 +856,9 @@ impl SchemaInner {
|
||||||
may: vec![],
|
may: vec![],
|
||||||
systemmust: vec![
|
systemmust: vec![
|
||||||
String::from("class"),
|
String::from("class"),
|
||||||
String::from("name"),
|
String::from("attributename"),
|
||||||
String::from("multivalue"),
|
String::from("multivalue"),
|
||||||
|
String::from("unique"),
|
||||||
String::from("syntax"),
|
String::from("syntax"),
|
||||||
String::from("description"),
|
String::from("description"),
|
||||||
],
|
],
|
||||||
|
@ -802,7 +881,7 @@ impl SchemaInner {
|
||||||
may: vec![],
|
may: vec![],
|
||||||
systemmust: vec![
|
systemmust: vec![
|
||||||
String::from("class"),
|
String::from("class"),
|
||||||
String::from("name"),
|
String::from("classname"),
|
||||||
String::from("description"),
|
String::from("description"),
|
||||||
],
|
],
|
||||||
must: vec![],
|
must: vec![],
|
||||||
|
@ -819,11 +898,7 @@ impl SchemaInner {
|
||||||
),
|
),
|
||||||
systemmay: vec![String::from("description"), String::from("name")],
|
systemmay: vec![String::from("description"), String::from("name")],
|
||||||
may: vec![],
|
may: vec![],
|
||||||
systemmust: vec![
|
systemmust: vec![String::from("class"), String::from("uuid")],
|
||||||
String::from("class"),
|
|
||||||
// String::from("name"),
|
|
||||||
String::from("uuid"),
|
|
||||||
],
|
|
||||||
must: vec![],
|
must: vec![],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -1253,7 +1328,8 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["schema_attr_test"],
|
"attributename": ["schema_attr_test"],
|
||||||
|
"unique": ["false"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
|
||||||
}
|
}
|
||||||
}"#,
|
}"#,
|
||||||
|
@ -1267,9 +1343,10 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["schema_attr_test"],
|
"attributename": ["schema_attr_test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"multivalue": ["false"],
|
"multivalue": ["false"],
|
||||||
|
"unique": ["false"],
|
||||||
"index": ["EQUALITY"],
|
"index": ["EQUALITY"],
|
||||||
"syntax": ["UTF8STRING"]
|
"syntax": ["UTF8STRING"]
|
||||||
}
|
}
|
||||||
|
@ -1284,10 +1361,11 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["schema_attr_test"],
|
"attributename": ["schema_attr_test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"description": ["Test attr parsing"],
|
"description": ["Test attr parsing"],
|
||||||
"multivalue": ["htouaoeu"],
|
"multivalue": ["htouaoeu"],
|
||||||
|
"unique": ["false"],
|
||||||
"index": ["EQUALITY"],
|
"index": ["EQUALITY"],
|
||||||
"syntax": ["UTF8STRING"]
|
"syntax": ["UTF8STRING"]
|
||||||
}
|
}
|
||||||
|
@ -1302,10 +1380,11 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["schema_attr_test"],
|
"attributename": ["schema_attr_test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"description": ["Test attr parsing"],
|
"description": ["Test attr parsing"],
|
||||||
"multivalue": ["false"],
|
"multivalue": ["false"],
|
||||||
|
"unique": ["false"],
|
||||||
"index": ["NTEHNOU"],
|
"index": ["NTEHNOU"],
|
||||||
"syntax": ["UTF8STRING"]
|
"syntax": ["UTF8STRING"]
|
||||||
}
|
}
|
||||||
|
@ -1320,10 +1399,11 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["schema_attr_test"],
|
"attributename": ["schema_attr_test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"description": ["Test attr parsing"],
|
"description": ["Test attr parsing"],
|
||||||
"multivalue": ["false"],
|
"multivalue": ["false"],
|
||||||
|
"unique": ["false"],
|
||||||
"index": ["EQUALITY"],
|
"index": ["EQUALITY"],
|
||||||
"syntax": ["TNEOUNTUH"]
|
"syntax": ["TNEOUNTUH"]
|
||||||
}
|
}
|
||||||
|
@ -1339,10 +1419,11 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["schema_attr_test"],
|
"attributename": ["schema_attr_test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"description": ["Test attr parsing"],
|
"description": ["Test attr parsing"],
|
||||||
"multivalue": ["false"],
|
"multivalue": ["false"],
|
||||||
|
"unique": ["false"],
|
||||||
"syntax": ["UTF8STRING"]
|
"syntax": ["UTF8STRING"]
|
||||||
}
|
}
|
||||||
}"#,
|
}"#,
|
||||||
|
@ -1357,10 +1438,11 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["schema_attr_test"],
|
"attributename": ["schema_attr_test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"description": ["Test attr parsing"],
|
"description": ["Test attr parsing"],
|
||||||
"multivalue": ["false"],
|
"multivalue": ["false"],
|
||||||
|
"unique": ["false"],
|
||||||
"index": ["EQUALITY"],
|
"index": ["EQUALITY"],
|
||||||
"syntax": ["UTF8STRING"]
|
"syntax": ["UTF8STRING"]
|
||||||
}
|
}
|
||||||
|
@ -1380,7 +1462,7 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "classtype"],
|
"class": ["object", "classtype"],
|
||||||
"name": ["schema_class_test"],
|
"classname": ["schema_class_test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
|
||||||
}
|
}
|
||||||
}"#,
|
}"#,
|
||||||
|
@ -1394,7 +1476,7 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object"],
|
"class": ["object"],
|
||||||
"name": ["schema_class_test"],
|
"classname": ["schema_class_test"],
|
||||||
"description": ["class test"],
|
"description": ["class test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
|
||||||
}
|
}
|
||||||
|
@ -1410,7 +1492,7 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "classtype"],
|
"class": ["object", "classtype"],
|
||||||
"name": ["schema_class_test"],
|
"classname": ["schema_class_test"],
|
||||||
"description": ["class test"],
|
"description": ["class test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"]
|
||||||
}
|
}
|
||||||
|
@ -1426,7 +1508,7 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "classtype"],
|
"class": ["object", "classtype"],
|
||||||
"name": ["schema_class_test"],
|
"classname": ["schema_class_test"],
|
||||||
"description": ["class test"],
|
"description": ["class test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"systemmust": ["d"]
|
"systemmust": ["d"]
|
||||||
|
@ -1442,7 +1524,7 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "classtype"],
|
"class": ["object", "classtype"],
|
||||||
"name": ["schema_class_test"],
|
"classname": ["schema_class_test"],
|
||||||
"description": ["class test"],
|
"description": ["class test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"systemmay": ["c"]
|
"systemmay": ["c"]
|
||||||
|
@ -1458,7 +1540,7 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "classtype"],
|
"class": ["object", "classtype"],
|
||||||
"name": ["schema_class_test"],
|
"classname": ["schema_class_test"],
|
||||||
"description": ["class test"],
|
"description": ["class test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"may": ["a"],
|
"may": ["a"],
|
||||||
|
@ -1475,7 +1557,7 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "classtype"],
|
"class": ["object", "classtype"],
|
||||||
"name": ["schema_class_test"],
|
"classname": ["schema_class_test"],
|
||||||
"description": ["class test"],
|
"description": ["class test"],
|
||||||
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
"uuid": ["66c68b2f-d02c-4243-8013-7946e40fe321"],
|
||||||
"may": ["a"],
|
"may": ["a"],
|
||||||
|
@ -1500,6 +1582,7 @@ mod tests {
|
||||||
uuid: Uuid::new_v4(),
|
uuid: Uuid::new_v4(),
|
||||||
description: String::from(""),
|
description: String::from(""),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
syntax: SyntaxType::UTF8STRING_INSENSITIVE,
|
||||||
};
|
};
|
||||||
|
@ -1521,6 +1604,7 @@ mod tests {
|
||||||
uuid: Uuid::new_v4(),
|
uuid: Uuid::new_v4(),
|
||||||
description: String::from(""),
|
description: String::from(""),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::UTF8STRING,
|
syntax: SyntaxType::UTF8STRING,
|
||||||
};
|
};
|
||||||
|
@ -1537,6 +1621,7 @@ mod tests {
|
||||||
uuid: Uuid::new_v4(),
|
uuid: Uuid::new_v4(),
|
||||||
description: String::from(""),
|
description: String::from(""),
|
||||||
multivalue: true,
|
multivalue: true,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::BOOLEAN,
|
syntax: SyntaxType::BOOLEAN,
|
||||||
};
|
};
|
||||||
|
@ -1559,6 +1644,7 @@ mod tests {
|
||||||
uuid: Uuid::new_v4(),
|
uuid: Uuid::new_v4(),
|
||||||
description: String::from(""),
|
description: String::from(""),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::SYNTAX_ID,
|
syntax: SyntaxType::SYNTAX_ID,
|
||||||
};
|
};
|
||||||
|
@ -1576,6 +1662,7 @@ mod tests {
|
||||||
uuid: Uuid::new_v4(),
|
uuid: Uuid::new_v4(),
|
||||||
description: String::from(""),
|
description: String::from(""),
|
||||||
multivalue: false,
|
multivalue: false,
|
||||||
|
unique: false,
|
||||||
index: vec![IndexType::EQUALITY],
|
index: vec![IndexType::EQUALITY],
|
||||||
syntax: SyntaxType::INDEX_ID,
|
syntax: SyntaxType::INDEX_ID,
|
||||||
};
|
};
|
||||||
|
@ -1667,9 +1754,10 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["testattr"],
|
"attributename": ["testattr"],
|
||||||
"description": ["testattr"],
|
"description": ["testattr"],
|
||||||
"multivalue": ["false"],
|
"multivalue": ["false"],
|
||||||
|
"unique": ["false"],
|
||||||
"syntax": ["UTF8STRING"],
|
"syntax": ["UTF8STRING"],
|
||||||
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||||
"zzzzz": ["zzzz"]
|
"zzzzz": ["zzzz"]
|
||||||
|
@ -1688,9 +1776,10 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["testattr"],
|
"attributename": ["testattr"],
|
||||||
"description": ["testattr"],
|
"description": ["testattr"],
|
||||||
"multivalue": ["zzzzz"],
|
"multivalue": ["zzzzz"],
|
||||||
|
"unique": ["false"],
|
||||||
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||||
"syntax": ["UTF8STRING"]
|
"syntax": ["UTF8STRING"]
|
||||||
}
|
}
|
||||||
|
@ -1708,9 +1797,10 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["testattr"],
|
"attributename": ["testattr"],
|
||||||
"description": ["testattr"],
|
"description": ["testattr"],
|
||||||
"multivalue": ["true"],
|
"multivalue": ["true"],
|
||||||
|
"unique": ["false"],
|
||||||
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||||
"syntax": ["UTF8STRING"]
|
"syntax": ["UTF8STRING"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1101,12 +1101,11 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.for_each(|er| er.apply_modlist(&me.modlist));
|
.for_each(|er| er.apply_modlist(&me.modlist));
|
||||||
|
|
||||||
// let mut candidates = try_audit!(au, candidates);
|
|
||||||
|
|
||||||
audit_log!(au, "modify: candidates -> {:?}", candidates);
|
audit_log!(au, "modify: candidates -> {:?}", candidates);
|
||||||
|
|
||||||
// Pre mod plugins
|
// Pre mod plugins
|
||||||
let mut audit_plugin_pre = AuditScope::new("plugin_pre_modify");
|
let mut audit_plugin_pre = AuditScope::new("plugin_pre_modify");
|
||||||
|
// We should probably supply the pre-post cands here.
|
||||||
let plug_pre_res =
|
let plug_pre_res =
|
||||||
Plugins::run_pre_modify(&mut audit_plugin_pre, self, &mut candidates, me);
|
Plugins::run_pre_modify(&mut audit_plugin_pre, self, &mut candidates, me);
|
||||||
au.append_scope(audit_plugin_pre);
|
au.append_scope(audit_plugin_pre);
|
||||||
|
@ -1122,9 +1121,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
// optimisations, this could be premature - so we for now, just
|
// optimisations, this could be premature - so we for now, just
|
||||||
// do the CORRECT thing and recommit as we may find later we always
|
// do the CORRECT thing and recommit as we may find later we always
|
||||||
// want to add CSN's or other.
|
// want to add CSN's or other.
|
||||||
//
|
|
||||||
// memberOf actually wants the pre cand list and the norm_cand list to see what
|
|
||||||
// changed. Could be optimised, but this is correct still ...
|
|
||||||
|
|
||||||
let res: Result<Vec<Entry<EntryValid, EntryCommitted>>, SchemaError> = candidates
|
let res: Result<Vec<Entry<EntryValid, EntryCommitted>>, SchemaError> = candidates
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -1149,6 +1145,9 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Post Plugins
|
// Post Plugins
|
||||||
|
//
|
||||||
|
// memberOf actually wants the pre cand list and the norm_cand list to see what
|
||||||
|
// changed. Could be optimised, but this is correct still ...
|
||||||
let mut audit_plugin_post = AuditScope::new("plugin_post_modify");
|
let mut audit_plugin_post = AuditScope::new("plugin_post_modify");
|
||||||
let plug_post_res = Plugins::run_post_modify(
|
let plug_post_res = Plugins::run_post_modify(
|
||||||
&mut audit_plugin_post,
|
&mut audit_plugin_post,
|
||||||
|
@ -2496,7 +2495,7 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "classtype"],
|
"class": ["object", "classtype"],
|
||||||
"name": ["testclass"],
|
"classname": ["testclass"],
|
||||||
"uuid": ["cfcae205-31c3-484b-8ced-667d1709c5e3"],
|
"uuid": ["cfcae205-31c3-484b-8ced-667d1709c5e3"],
|
||||||
"description": ["Test Class"]
|
"description": ["Test Class"]
|
||||||
}
|
}
|
||||||
|
@ -2529,7 +2528,7 @@ mod tests {
|
||||||
// delete the class
|
// delete the class
|
||||||
let de_class = unsafe {
|
let de_class = unsafe {
|
||||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||||
"name",
|
"classname",
|
||||||
PartialValue::new_iutf8s("testclass")
|
PartialValue::new_iutf8s("testclass")
|
||||||
)))
|
)))
|
||||||
};
|
};
|
||||||
|
@ -2580,10 +2579,11 @@ mod tests {
|
||||||
"state": null,
|
"state": null,
|
||||||
"attrs": {
|
"attrs": {
|
||||||
"class": ["object", "attributetype"],
|
"class": ["object", "attributetype"],
|
||||||
"name": ["testattr"],
|
"attributename": ["testattr"],
|
||||||
"uuid": ["cfcae205-31c3-484b-8ced-667d1709c5e3"],
|
"uuid": ["cfcae205-31c3-484b-8ced-667d1709c5e3"],
|
||||||
"description": ["Test Attribute"],
|
"description": ["Test Attribute"],
|
||||||
"multivalue": ["false"],
|
"multivalue": ["false"],
|
||||||
|
"unique": ["false"],
|
||||||
"syntax": ["UTF8STRING"]
|
"syntax": ["UTF8STRING"]
|
||||||
}
|
}
|
||||||
}"#,
|
}"#,
|
||||||
|
@ -2615,7 +2615,7 @@ mod tests {
|
||||||
// delete the attr
|
// delete the attr
|
||||||
let de_attr = unsafe {
|
let de_attr = unsafe {
|
||||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||||
"name",
|
"attributename",
|
||||||
PartialValue::new_iutf8s("testattr")
|
PartialValue::new_iutf8s("testattr")
|
||||||
)))
|
)))
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue