cargo fmt

This commit is contained in:
William Brown 2019-01-29 17:17:28 +10:00
parent 66e087787a
commit 63e600d49e
9 changed files with 252 additions and 213 deletions

View file

@ -8,7 +8,7 @@ use serde_json;
// use uuid; // use uuid;
use audit::AuditScope; use audit::AuditScope;
use entry::{Entry, EntryValid, EntryNew, EntryCommitted}; use entry::{Entry, EntryCommitted, EntryNew, EntryValid};
use filter::Filter; use filter::Filter;
mod idl; mod idl;
@ -53,7 +53,11 @@ pub trait BackendReadTransaction {
fn get_conn(&self) -> &r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>; fn get_conn(&self) -> &r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
// Take filter, and AuditScope ref? // Take filter, and AuditScope ref?
fn search(&self, au: &mut AuditScope, filt: &Filter) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, BackendError> { fn search(
&self,
au: &mut AuditScope,
filt: &Filter,
) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, BackendError> {
// Do things // Do things
// Alloc a vec for the entries. // Alloc a vec for the entries.
// FIXME: Make this actually a good size for the result set ... // FIXME: Make this actually a good size for the result set ...
@ -97,7 +101,8 @@ pub trait BackendReadTransaction {
.iter() .iter()
.filter_map(|id_ent| { .filter_map(|id_ent| {
// TODO: Should we do better than unwrap? // TODO: Should we do better than unwrap?
let mut e: Entry<EntryValid, EntryCommitted> = serde_json::from_str(id_ent.data.as_str()).unwrap(); let mut e: Entry<EntryValid, EntryCommitted> =
serde_json::from_str(id_ent.data.as_str()).unwrap();
e.id = Some(id_ent.id); e.id = Some(id_ent.id);
if e.entry_match_no_index(&filt) { if e.entry_match_no_index(&filt) {
Some(e) Some(e)
@ -206,10 +211,14 @@ impl BackendWriteTransaction {
} }
fn get_id2entry_max_id(&self) -> i64 { fn get_id2entry_max_id(&self) -> i64 {
let mut stmt = self.conn.prepare("SELECT MAX(id) as id_max FROM id2entry").unwrap(); let mut stmt = self
.conn
.prepare("SELECT MAX(id) as id_max FROM id2entry")
.unwrap();
assert!(stmt.exists(NO_PARAMS).unwrap()); assert!(stmt.exists(NO_PARAMS).unwrap());
let i: Option<i64> = stmt.query_row(NO_PARAMS, |row| row.get(0)) let i: Option<i64> = stmt
.query_row(NO_PARAMS, |row| row.get(0))
.expect("failed to execute"); .expect("failed to execute");
match i { match i {
Some(e) => e, Some(e) => e,
@ -217,7 +226,11 @@ impl BackendWriteTransaction {
} }
} }
pub fn create(&self, au: &mut AuditScope, entries: &Vec<Entry<EntryValid, EntryNew>>) -> Result<(), BackendError> { pub fn create(
&self,
au: &mut AuditScope,
entries: &Vec<Entry<EntryValid, EntryNew>>,
) -> Result<(), BackendError> {
audit_segment!(au, || { audit_segment!(au, || {
// Start be audit timer // Start be audit timer
@ -273,7 +286,11 @@ impl BackendWriteTransaction {
}) })
} }
pub fn modify(&self, au: &mut AuditScope, entries: &Vec<Entry<EntryValid, EntryCommitted>>) -> Result<(), BackendError> { pub fn modify(
&self,
au: &mut AuditScope,
entries: &Vec<Entry<EntryValid, EntryCommitted>>,
) -> Result<(), BackendError> {
if entries.is_empty() { if entries.is_empty() {
// TODO: Better error // TODO: Better error
return Err(BackendError::EmptyRequest); return Err(BackendError::EmptyRequest);
@ -291,7 +308,7 @@ impl BackendWriteTransaction {
data: serde_json::to_string(&e).unwrap(), data: serde_json::to_string(&e).unwrap(),
}) })
} }
None => None None => None,
} }
}) })
.collect(); .collect();
@ -307,20 +324,25 @@ impl BackendWriteTransaction {
// Now, given the list of id's, update them // Now, given the list of id's, update them
{ {
// TODO: ACTUALLY HANDLE THIS ERROR WILLIAM YOU LAZY SHIT. // TODO: ACTUALLY HANDLE THIS ERROR WILLIAM YOU LAZY SHIT.
let mut stmt = self.conn.prepare("UPDATE id2entry SET data = :data WHERE id = :id").unwrap(); let mut stmt = self
.conn
.prepare("UPDATE id2entry SET data = :data WHERE id = :id")
.unwrap();
ser_entries.iter().for_each(|ser_ent| { ser_entries.iter().for_each(|ser_ent| {
stmt.execute_named(&[ stmt.execute_named(&[(":id", &ser_ent.id), (":data", &ser_ent.data)])
(":id", &ser_ent.id), .unwrap();
(":data", &ser_ent.data),
]).unwrap();
}); });
} }
Ok(()) Ok(())
} }
pub fn delete(&self, au: &mut AuditScope, entries: &Vec<Entry<EntryValid, EntryCommitted>>) -> Result<(), BackendError> { pub fn delete(
&self,
au: &mut AuditScope,
entries: &Vec<Entry<EntryValid, EntryCommitted>>,
) -> Result<(), BackendError> {
// Perform a search for the entries --> This is a problem for the caller // Perform a search for the entries --> This is a problem for the caller
if entries.is_empty() { if entries.is_empty() {
@ -329,11 +351,7 @@ impl BackendWriteTransaction {
} }
// Assert the Id's exist on the entry. // Assert the Id's exist on the entry.
let id_list: Vec<i64> = entries.iter() let id_list: Vec<i64> = entries.iter().filter_map(|entry| entry.id).collect();
.filter_map(|entry| {
entry.id
})
.collect();
// Simple: If the list of id's is not the same as the input list, we are missing id's // Simple: If the list of id's is not the same as the input list, we are missing id's
// TODO: This check won't be needed once I rebuild the entry state types. // TODO: This check won't be needed once I rebuild the entry state types.
@ -348,7 +366,10 @@ impl BackendWriteTransaction {
// probably okay with this. // probably okay with this.
// TODO: ACTUALLY HANDLE THIS ERROR WILLIAM YOU LAZY SHIT. // TODO: ACTUALLY HANDLE THIS ERROR WILLIAM YOU LAZY SHIT.
let mut stmt = self.conn.prepare("DELETE FROM id2entry WHERE id = :id").unwrap(); let mut stmt = self
.conn
.prepare("DELETE FROM id2entry WHERE id = :id")
.unwrap();
id_list.iter().for_each(|id| { id_list.iter().for_each(|id| {
stmt.execute(&[id]).unwrap(); stmt.execute(&[id]).unwrap();
@ -532,7 +553,7 @@ mod tests {
extern crate tokio; extern crate tokio;
use super::super::audit::AuditScope; use super::super::audit::AuditScope;
use super::super::entry::{Entry, EntryInvalid, EntryValid, EntryNew, EntryCommitted}; use super::super::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
use super::super::filter::Filter; use super::super::filter::Filter;
use super::{ use super::{
Backend, BackendError, BackendReadTransaction, BackendTransaction, BackendWriteTransaction, Backend, BackendError, BackendReadTransaction, BackendTransaction, BackendWriteTransaction,
@ -560,7 +581,7 @@ mod tests {
let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap(); let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap();
let entries = $be.search($audit, &filt).unwrap(); let entries = $be.search($audit, &filt).unwrap();
entries.first().is_some() entries.first().is_some()
}} }};
} }
macro_rules! entry_attr_pres { macro_rules! entry_attr_pres {
@ -569,12 +590,10 @@ mod tests {
let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap(); let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap();
let entries = $be.search($audit, &filt).unwrap(); let entries = $be.search($audit, &filt).unwrap();
match entries.first() { match entries.first() {
Some(ent) => { Some(ent) => ent.attribute_pres($attr),
ent.attribute_pres($attr) None => false,
} }
None => false }};
}
}}
} }
#[test] #[test]
@ -625,7 +644,9 @@ mod tests {
assert!(entry_exists!(audit, be, e2)); assert!(entry_exists!(audit, be, e2));
// You need to now retrieve the entries back out to get the entry id's // You need to now retrieve the entries back out to get the entry id's
let mut results = be.search(audit, &Filter::Pres(String::from("userid"))).unwrap(); let mut results = be
.search(audit, &Filter::Pres(String::from("userid")))
.unwrap();
// Get these out to usable entries. // Get these out to usable entries.
let r1 = results.remove(0); let r1 = results.remove(0);
@ -689,9 +710,10 @@ mod tests {
assert!(entry_exists!(audit, be, e2)); assert!(entry_exists!(audit, be, e2));
assert!(entry_exists!(audit, be, e3)); assert!(entry_exists!(audit, be, e3));
// You need to now retrieve the entries back out to get the entry id's // You need to now retrieve the entries back out to get the entry id's
let mut results = be.search(audit, &Filter::Pres(String::from("userid"))).unwrap(); let mut results = be
.search(audit, &Filter::Pres(String::from("userid")))
.unwrap();
// Get these out to usable entries. // Get these out to usable entries.
let r1 = results.remove(0); let r1 = results.remove(0);
@ -727,7 +749,6 @@ mod tests {
// delete none (no entries left) // delete none (no entries left)
// see fn delete for why this is ok, not err // see fn delete for why this is ok, not err
assert!(be.delete(audit, &vec![r2.clone(), r3.clone()]).is_ok()); assert!(be.delete(audit, &vec![r2.clone(), r3.clone()]).is_ok());
}); });
} }
} }

View file

@ -1,14 +1,14 @@
// use serde_json::{Error, Value}; // use serde_json::{Error, Value};
use super::proto_v1::Entry as ProtoEntry; use super::proto_v1::Entry as ProtoEntry;
use error::SchemaError;
use filter::Filter; use filter::Filter;
use modify::{Modify, ModifyList};
use schema::{SchemaAttribute, SchemaClass, SchemaReadTransaction};
use std::collections::btree_map::{Iter as BTreeIter, IterMut as BTreeIterMut}; use std::collections::btree_map::{Iter as BTreeIter, IterMut as BTreeIterMut};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::collections::HashMap; use std::collections::HashMap;
use std::slice::Iter as SliceIter;
use modify::{Modify, ModifyList};
use schema::{SchemaReadTransaction, SchemaAttribute, SchemaClass};
use error::SchemaError;
use std::iter::ExactSizeIterator; use std::iter::ExactSizeIterator;
use std::slice::Iter as SliceIter;
// make a trait entry for everything to adhere to? // make a trait entry for everything to adhere to?
// * How to get indexs out? // * How to get indexs out?
@ -175,10 +175,18 @@ impl Entry<EntryInvalid, EntryNew> {
} }
impl<STATE> Entry<EntryInvalid, STATE> { impl<STATE> Entry<EntryInvalid, STATE> {
pub fn validate(self, schema: &SchemaReadTransaction) -> Result<Entry<EntryValid, STATE>, SchemaError> { pub fn validate(
self,
schema: &SchemaReadTransaction,
) -> Result<Entry<EntryValid, STATE>, SchemaError> {
// We need to clone before we start, as well be mutating content. // We need to clone before we start, as well be mutating content.
// We destructure: // We destructure:
let Entry { valid, state, id, attrs } = self; let Entry {
valid,
state,
id,
attrs,
} = self;
let schema_classes = schema.get_classes(); let schema_classes = schema.get_classes();
let schema_attributes = schema.get_attributes(); let schema_attributes = schema.get_attributes();
@ -232,20 +240,16 @@ impl<STATE> Entry<EntryInvalid, STATE> {
{ {
// First, check we have class on the object .... // First, check we have class on the object ....
if !ne.attribute_pres("class") { if !ne.attribute_pres("class") {
return Err(SchemaError::InvalidClass) return Err(SchemaError::InvalidClass);
} }
let entry_classes = ne.classes(); let entry_classes = ne.classes();
let entry_classes_size = entry_classes.len(); let entry_classes_size = entry_classes.len();
let classes: HashMap<String, &SchemaClass> = entry_classes let classes: HashMap<String, &SchemaClass> = entry_classes
.filter_map(|c| { .filter_map(|c| match schema_classes.get(c) {
match schema_classes.get(c) { Some(cls) => Some((c.clone(), cls)),
Some(cls) => {
Some((c.clone(), cls))
}
None => None, None => None,
}
}) })
.collect(); .collect();
@ -253,7 +257,6 @@ impl<STATE> Entry<EntryInvalid, STATE> {
return Err(SchemaError::InvalidClass); return Err(SchemaError::InvalidClass);
}; };
let extensible = classes.contains_key("extensibleobject"); let extensible = classes.contains_key("extensibleobject");
// What this is really doing is taking a set of classes, and building an // What this is really doing is taking a set of classes, and building an
@ -287,9 +290,7 @@ impl<STATE> Entry<EntryInvalid, STATE> {
for (attr_name, _attr) in must { for (attr_name, _attr) in must {
let avas = ne.get_ava(&attr_name); let avas = ne.get_ava(&attr_name);
if avas.is_none() { if avas.is_none() {
return Err(SchemaError::MissingMustAttribute( return Err(SchemaError::MissingMustAttribute(String::from(attr_name)));
String::from(attr_name)
));
} }
} }
@ -304,7 +305,7 @@ impl<STATE> Entry<EntryInvalid, STATE> {
// We have to destructure here to make type checker happy // We have to destructure here to make type checker happy
match r { match r {
Ok(_) => {} Ok(_) => {}
Err(e) => return Err(e) Err(e) => return Err(e),
} }
} }
None => { None => {
@ -322,7 +323,8 @@ impl<STATE> Entry<EntryInvalid, STATE> {
} }
impl<VALID, STATE> Clone for Entry<VALID, STATE> impl<VALID, STATE> Clone for Entry<VALID, STATE>
where VALID: Copy, where
VALID: Copy,
STATE: Copy, STATE: Copy,
{ {
// Dirty modifiable state. Works on any other state to dirty them. // Dirty modifiable state. Works on any other state to dirty them.
@ -381,7 +383,7 @@ impl<STATE> Entry<EntryValid, STATE> {
valid: EntryInvalid, valid: EntryInvalid,
state: self.state, state: self.state,
id: self.id, id: self.id,
attrs: self.attrs attrs: self.attrs,
} }
} }
@ -390,7 +392,7 @@ impl<STATE> Entry<EntryValid, STATE> {
valid: self.valid, valid: self.valid,
state: EntryCommitted, state: EntryCommitted,
id: self.id, id: self.id,
attrs: self.attrs attrs: self.attrs,
} }
} }
@ -400,34 +402,28 @@ impl<STATE> Entry<EntryValid, STATE> {
// This is recursive!!!! // This is recursive!!!!
match filter { match filter {
Filter::Eq(attr, value) => self.attribute_equality(attr.as_str(), value.as_str()), Filter::Eq(attr, value) => self.attribute_equality(attr.as_str(), value.as_str()),
Filter::Sub(attr, subvalue) => self.attribute_substring(attr.as_str(), subvalue.as_str()), Filter::Sub(attr, subvalue) => {
self.attribute_substring(attr.as_str(), subvalue.as_str())
}
Filter::Pres(attr) => { Filter::Pres(attr) => {
// Given attr, is is present in the entry? // Given attr, is is present in the entry?
self.attribute_pres(attr.as_str()) self.attribute_pres(attr.as_str())
} }
Filter::Or(l) => { Filter::Or(l) => l.iter().fold(false, |acc, f| {
l.iter()
.fold(false, |acc, f| {
if acc { if acc {
acc acc
} else { } else {
self.entry_match_no_index(f) self.entry_match_no_index(f)
} }
}) }),
} Filter::And(l) => l.iter().fold(true, |acc, f| {
Filter::And(l) => {
l.iter()
.fold(true, |acc, f| {
if acc { if acc {
self.entry_match_no_index(f) self.entry_match_no_index(f)
} else { } else {
acc acc
} }
}) }),
} Filter::Not(f) => !self.entry_match_no_index(f),
Filter::Not(f) => {
!self.entry_match_no_index(f)
}
} }
} }
@ -473,8 +469,7 @@ impl<STATE> Entry<EntryValid, STATE> {
} }
} }
pub fn gen_modlist_assert(&self, schema: &SchemaReadTransaction) -> Result<ModifyList, ()> pub fn gen_modlist_assert(&self, schema: &SchemaReadTransaction) -> Result<ModifyList, ()> {
{
// Create a modlist from this entry. We make this assuming we want the entry // Create a modlist from this entry. We make this assuming we want the entry
// to have this one as a subset of values. This means if we have single // to have this one as a subset of values. This means if we have single
// values, we'll replace, if they are multivalue, we present them. // values, we'll replace, if they are multivalue, we present them.
@ -490,9 +485,7 @@ impl<STATE> Entry<EntryValid, STATE> {
mods.push_mod(Modify::Purged(k.clone())); mods.push_mod(Modify::Purged(k.clone()));
} }
} }
Err(e) => { Err(e) => return Err(()),
return Err(())
}
} }
for v in vs { for v in vs {
mods.push_mod(Modify::Present(k.clone(), v.clone())); mods.push_mod(Modify::Present(k.clone(), v.clone()));
@ -535,7 +528,11 @@ impl<VALID, STATE> Entry<VALID, STATE> {
// Get the class vec, if any? // Get the class vec, if any?
// How do we indicate "empty?" // How do we indicate "empty?"
// FIXME: Actually handle this error ... // FIXME: Actually handle this error ...
let v = self.attrs.get("class").map(|c| c.len()).expect("INVALID STATE, NO CLASS FOUND"); let v = self
.attrs
.get("class")
.map(|c| c.len())
.expect("INVALID STATE, NO CLASS FOUND");
let c = self.attrs.get("class").map(|c| c.iter()); let c = self.attrs.get("class").map(|c| c.iter());
EntryClasses { size: v, inner: c } EntryClasses { size: v, inner: c }
} }
@ -548,7 +545,8 @@ impl<VALID, STATE> Entry<VALID, STATE> {
} }
impl<STATE> Entry<EntryInvalid, STATE> impl<STATE> Entry<EntryInvalid, STATE>
where STATE: Copy, where
STATE: Copy,
{ {
// This should always work? It's only on validate that we'll build // This should always work? It's only on validate that we'll build
// a list of syntax violations ... // a list of syntax violations ...
@ -589,8 +587,7 @@ impl<STATE> Entry<EntryInvalid, STATE>
v.remove(idx); v.remove(idx);
} }
// It does not exist, move on. // It does not exist, move on.
Err(_) => { Err(_) => {}
}
} }
}); });
} }
@ -618,8 +615,7 @@ impl<STATE> Entry<EntryInvalid, STATE>
// This is effectively clone-and-transform // This is effectively clone-and-transform
// clone the entry // clone the entry
let mut ne: Entry<EntryInvalid, STATE> = let mut ne: Entry<EntryInvalid, STATE> = Entry {
Entry {
valid: self.valid, valid: self.valid,
state: self.state, state: self.state,
id: self.id, id: self.id,
@ -629,15 +625,9 @@ impl<STATE> Entry<EntryInvalid, STATE>
// mutate // mutate
for modify in modlist.mods.iter() { for modify in modlist.mods.iter() {
match modify { match modify {
Modify::Present(a, v) => { Modify::Present(a, v) => ne.add_ava(a.clone(), v.clone()),
ne.add_ava(a.clone(), v.clone()) Modify::Removed(a, v) => ne.remove_ava(a, v),
} Modify::Purged(a) => ne.purge_ava(a),
Modify::Removed(a, v) => {
ne.remove_ava(a, v)
}
Modify::Purged(a) => {
ne.purge_ava(a)
}
} }
} }
@ -745,16 +735,16 @@ mod tests {
let mut e: Entry<EntryInvalid, EntryNew> = Entry::new(); let mut e: Entry<EntryInvalid, EntryNew> = Entry::new();
e.add_ava(String::from("userid"), String::from("william")); e.add_ava(String::from("userid"), String::from("william"));
let mods = ModifyList::new_list(vec![ let mods = ModifyList::new_list(vec![Modify::Present(
Modify::Present(String::from("attr"), String::from("value")), String::from("attr"),
]); String::from("value"),
)]);
let ne = e.apply_modlist(&mods).unwrap(); let ne = e.apply_modlist(&mods).unwrap();
// Assert the changes are there // Assert the changes are there
assert!(ne.attribute_equality("attr", "value")); assert!(ne.attribute_equality("attr", "value"));
// Assert present for multivalue // Assert present for multivalue
// Assert purge on single/multi/empty value // Assert purge on single/multi/empty value
// Assert removed on value that exists and doesn't exist // Assert removed on value that exists and doesn't exist

View file

@ -2,7 +2,7 @@ use super::filter::Filter;
use super::proto_v1::Entry as ProtoEntry; use super::proto_v1::Entry as ProtoEntry;
use super::proto_v1::{CreateRequest, Response, SearchRequest, SearchResponse}; use super::proto_v1::{CreateRequest, Response, SearchRequest, SearchResponse};
use actix::prelude::*; use actix::prelude::*;
use entry::{Entry, EntryInvalid, EntryNew, EntryValid, EntryCommitted}; use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
use error::OperationError; use error::OperationError;
use modify::ModifyList; use modify::ModifyList;
@ -185,4 +185,3 @@ impl ModifyEvent {
} }
} }
} }

View file

@ -2,8 +2,8 @@
// in parallel map/reduce style, or directly on a single // in parallel map/reduce style, or directly on a single
// entry to assert it matches. // entry to assert it matches.
use std::cmp::{Ordering, PartialOrd};
use regex::Regex; use regex::Regex;
use std::cmp::{Ordering, PartialOrd};
// Perhaps make these json serialisable. Certainly would make parsing // Perhaps make these json serialisable. Certainly would make parsing
// simpler ... // simpler ...
@ -102,7 +102,7 @@ impl PartialOrd for Filter {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::Filter; use super::Filter;
use entry::{Entry, EntryValid, EntryNew}; use entry::{Entry, EntryNew, EntryValid};
use serde_json; use serde_json;
use std::cmp::{Ordering, PartialOrd}; use std::cmp::{Ordering, PartialOrd};
@ -199,14 +199,17 @@ mod tests {
#[test] #[test]
fn test_or_entry_filter() { fn test_or_entry_filter() {
let e: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{ let e: Entry<EntryValid, EntryNew> = serde_json::from_str(
r#"{
"valid": null, "valid": null,
"state": null, "state": null,
"attrs": { "attrs": {
"userid": ["william"], "userid": ["william"],
"uidNumber": ["1000"] "uidNumber": ["1000"]
} }
}"#).unwrap(); }"#,
)
.unwrap();
let f_t1a = Filter::Or(vec![ let f_t1a = Filter::Or(vec![
Filter::Eq(String::from("userid"), String::from("william")), Filter::Eq(String::from("userid"), String::from("william")),
@ -235,14 +238,17 @@ mod tests {
#[test] #[test]
fn test_and_entry_filter() { fn test_and_entry_filter() {
let e: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{ let e: Entry<EntryValid, EntryNew> = serde_json::from_str(
r#"{
"valid": null, "valid": null,
"state": null, "state": null,
"attrs": { "attrs": {
"userid": ["william"], "userid": ["william"],
"uidNumber": ["1000"] "uidNumber": ["1000"]
} }
}"#).unwrap(); }"#,
)
.unwrap();
let f_t1a = Filter::And(vec![ let f_t1a = Filter::And(vec![
Filter::Eq(String::from("userid"), String::from("william")), Filter::Eq(String::from("userid"), String::from("william")),
@ -271,64 +277,80 @@ mod tests {
#[test] #[test]
fn test_not_entry_filter() { fn test_not_entry_filter() {
let e1: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{ let e1: Entry<EntryValid, EntryNew> = serde_json::from_str(
r#"{
"valid": null, "valid": null,
"state": null, "state": null,
"attrs": { "attrs": {
"userid": ["william"], "userid": ["william"],
"uidNumber": ["1000"] "uidNumber": ["1000"]
} }
}"#).unwrap(); }"#,
)
.unwrap();
let f_t1a = Filter::Not(Box::new( let f_t1a = Filter::Not(Box::new(Filter::Eq(
Filter::Eq(String::from("userid"), String::from("alice")), String::from("userid"),
)); String::from("alice"),
)));
assert!(e1.entry_match_no_index(&f_t1a)); assert!(e1.entry_match_no_index(&f_t1a));
let f_t2a = Filter::Not(Box::new( let f_t2a = Filter::Not(Box::new(Filter::Eq(
Filter::Eq(String::from("userid"), String::from("william")), String::from("userid"),
)); String::from("william"),
)));
assert!(!e1.entry_match_no_index(&f_t2a)); assert!(!e1.entry_match_no_index(&f_t2a));
} }
#[test] #[test]
fn test_nested_entry_filter() { fn test_nested_entry_filter() {
let e1: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{ let e1: Entry<EntryValid, EntryNew> = serde_json::from_str(
r#"{
"valid": null, "valid": null,
"state": null, "state": null,
"attrs": { "attrs": {
"class": ["person"], "class": ["person"],
"uidNumber": ["1000"] "uidNumber": ["1000"]
} }
}"#).unwrap(); }"#,
)
.unwrap();
let e2: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{ let e2: Entry<EntryValid, EntryNew> = serde_json::from_str(
r#"{
"valid": null, "valid": null,
"state": null, "state": null,
"attrs": { "attrs": {
"class": ["person"], "class": ["person"],
"uidNumber": ["1001"] "uidNumber": ["1001"]
} }
}"#).unwrap(); }"#,
)
.unwrap();
let e3: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{ let e3: Entry<EntryValid, EntryNew> = serde_json::from_str(
r#"{
"valid": null, "valid": null,
"state": null, "state": null,
"attrs": { "attrs": {
"class": ["person"], "class": ["person"],
"uidNumber": ["1002"] "uidNumber": ["1002"]
} }
}"#).unwrap(); }"#,
)
.unwrap();
let e4: Entry<EntryValid, EntryNew> = serde_json::from_str(r#"{ let e4: Entry<EntryValid, EntryNew> = serde_json::from_str(
r#"{
"valid": null, "valid": null,
"state": null, "state": null,
"attrs": { "attrs": {
"class": ["group"], "class": ["group"],
"uidNumber": ["1000"] "uidNumber": ["1000"]
} }
}"#).unwrap(); }"#,
)
.unwrap();
let f_t1a = Filter::And(vec![ let f_t1a = Filter::And(vec![
Filter::Eq(String::from("class"), String::from("person")), Filter::Eq(String::from("class"), String::from("person")),

View file

@ -39,10 +39,10 @@ mod constants;
mod entry; mod entry;
mod event; mod event;
mod identity; mod identity;
mod modify;
mod plugins; mod plugins;
mod schema; mod schema;
mod server; mod server;
mod modify;
pub mod config; pub mod config;
pub mod core; pub mod core;

View file

@ -133,7 +133,7 @@ mod tests {
use audit::AuditScope; use audit::AuditScope;
use be::{Backend, BackendWriteTransaction}; use be::{Backend, BackendWriteTransaction};
use entry::{Entry, EntryValid, EntryInvalid, EntryNew}; use entry::{Entry, EntryInvalid, EntryNew, EntryValid};
use event::CreateEvent; use event::CreateEvent;
use schema::{Schema, SchemaWriteTransaction}; use schema::{Schema, SchemaWriteTransaction};

View file

@ -75,3 +75,23 @@ impl CreateRequest {
// //
// On loginSuccess, we send a cookie, and that allows the token to be // On loginSuccess, we send a cookie, and that allows the token to be
// generated. The cookie can be shared between servers. // generated. The cookie can be shared between servers.
// Request auth for identity X
pub struct AuthRequest {}
// Respond with the list of auth types and nonce, etc.
pub struct AuthResponse {}
// Provide responses
pub struct AuthProvide {}
// After authprovide, we can move to AuthResponse (for more)
// or below ...
// Go away.
// Provide reason?
pub struct AuthDenied {}
// Welcome friend.
// On success provide entry "self", for group assertions?
pub struct AuthSuccess {}

View file

@ -5,11 +5,11 @@ use super::error::SchemaError;
use super::filter::Filter; use super::filter::Filter;
use std::collections::HashMap; use std::collections::HashMap;
// Apparently this is nightly only? // Apparently this is nightly only?
use modify::ModifyList;
use regex::Regex; use regex::Regex;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::str::FromStr; use std::str::FromStr;
use uuid::Uuid; use uuid::Uuid;
use modify::ModifyList;
use concread::cowcell::{CowCell, CowCellReadTxn, CowCellWriteTxn}; use concread::cowcell::{CowCell, CowCellReadTxn, CowCellWriteTxn};
@ -917,9 +917,7 @@ impl SchemaInner {
} }
}) })
} }
Filter::Not(filter) => { Filter::Not(filter) => self.validate_filter(filter),
self.validate_filter(filter)
}
} }
} }
@ -932,9 +930,7 @@ impl SchemaInner {
fn is_multivalue(&self, attr_name: &str) -> Result<bool, SchemaError> { fn is_multivalue(&self, attr_name: &str) -> Result<bool, SchemaError> {
match self.attributes.get(attr_name) { match self.attributes.get(attr_name) {
Some(a_schema) => { Some(a_schema) => Ok(a_schema.multivalue),
Ok(a_schema.multivalue)
}
None => { None => {
return Err(SchemaError::InvalidAttribute); return Err(SchemaError::InvalidAttribute);
} }
@ -1009,7 +1005,7 @@ impl Schema {
mod tests { mod tests {
use super::super::audit::AuditScope; use super::super::audit::AuditScope;
use super::super::constants::*; use super::super::constants::*;
use super::super::entry::{Entry, EntryValid, EntryInvalid, EntryNew}; use super::super::entry::{Entry, EntryInvalid, EntryNew, EntryValid};
use super::super::error::SchemaError; use super::super::error::SchemaError;
use super::super::filter::Filter; use super::super::filter::Filter;
use super::{IndexType, Schema, SchemaAttribute, SchemaClass, SyntaxType}; use super::{IndexType, Schema, SchemaAttribute, SchemaClass, SyntaxType};
@ -1238,10 +1234,7 @@ mod tests {
) )
.unwrap(); .unwrap();
assert_eq!( assert_eq!(e_no_class.validate(&schema), Err(SchemaError::InvalidClass));
e_no_class.validate(&schema),
Err(SchemaError::InvalidClass)
);
let e_bad_class: Entry<EntryInvalid, EntryNew> = serde_json::from_str( let e_bad_class: Entry<EntryInvalid, EntryNew> = serde_json::from_str(
r#"{ r#"{

View file

@ -10,15 +10,16 @@ use be::{
}; };
use constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1}; use constants::{JSON_ANONYMOUS_V1, JSON_SYSTEM_INFO_V1};
use entry::{Entry, EntryNew, EntryCommitted, EntryValid, EntryInvalid}; use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
use error::{OperationError, SchemaError}; use error::{OperationError, SchemaError};
use event::{CreateEvent, ExistsEvent, OpResult, SearchEvent, SearchResult, DeleteEvent, ModifyEvent}; use event::{
CreateEvent, DeleteEvent, ExistsEvent, ModifyEvent, OpResult, SearchEvent, SearchResult,
};
use filter::Filter; use filter::Filter;
use log::EventLog; use log::EventLog;
use plugins::Plugins;
use schema::{Schema, SchemaTransaction, SchemaReadTransaction, SchemaWriteTransaction};
use modify::ModifyList; use modify::ModifyList;
use plugins::Plugins;
use schema::{Schema, SchemaReadTransaction, SchemaTransaction, SchemaWriteTransaction};
pub fn start(log: actix::Addr<EventLog>, path: &str, threads: usize) -> actix::Addr<QueryServer> { pub fn start(log: actix::Addr<EventLog>, path: &str, threads: usize) -> actix::Addr<QueryServer> {
let mut audit = AuditScope::new("server_start"); let mut audit = AuditScope::new("server_start");
@ -89,7 +90,11 @@ pub trait QueryServerReadTransaction {
fn get_be_txn(&self) -> &Self::BackendTransactionType; fn get_be_txn(&self) -> &Self::BackendTransactionType;
fn search(&self, au: &mut AuditScope, se: &SearchEvent) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, OperationError> { fn search(
&self,
au: &mut AuditScope,
se: &SearchEvent,
) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, OperationError> {
// TODO: Validate the filter // TODO: Validate the filter
// This is an important security step because it prevents us from // This is an important security step because it prevents us from
// performing un-indexed searches on attr's that don't exist in the // performing un-indexed searches on attr's that don't exist in the
@ -141,8 +146,11 @@ pub trait QueryServerReadTransaction {
res res
} }
fn internal_search(&self, audit: &mut AuditScope, filter: Filter) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, OperationError> { fn internal_search(
&self,
audit: &mut AuditScope,
filter: Filter,
) -> Result<Vec<Entry<EntryValid, EntryCommitted>>, OperationError> {
let mut audit_int = AuditScope::new("internal_search"); let mut audit_int = AuditScope::new("internal_search");
let se = SearchEvent::new_internal(filter); let se = SearchEvent::new_internal(filter);
let res = self.search(&mut audit_int, &se); let res = self.search(&mut audit_int, &se);
@ -240,7 +248,8 @@ impl<'a> QueryServerWriteTransaction<'a> {
// based on request size in the frontend? // based on request size in the frontend?
// Copy the entries to a writeable form. // Copy the entries to a writeable form.
let mut candidates: Vec<Entry<EntryInvalid, EntryNew>> = ce.entries.iter().map(|er| er.clone()).collect(); let mut candidates: Vec<Entry<EntryInvalid, EntryNew>> =
ce.entries.iter().map(|er| er.clone()).collect();
// run any pre plugins, giving them the list of mutable candidates. // run any pre plugins, giving them the list of mutable candidates.
// pre-plugins are defined here in their correct order of calling! // pre-plugins are defined here in their correct order of calling!
@ -261,15 +270,13 @@ impl<'a> QueryServerWriteTransaction<'a> {
return plug_pre_res; return plug_pre_res;
} }
let (norm_cand, invalid_cand): let (norm_cand, invalid_cand): (
(Vec<Result<Entry<EntryValid, EntryNew>, _>>, Vec<Result<Entry<EntryValid, EntryNew>, _>>,
Vec<Result<_, SchemaError>>) = candidates.into_iter() Vec<Result<_, SchemaError>>,
.map(|e| { ) = candidates
e.validate(&self.schema) .into_iter()
}) .map(|e| e.validate(&self.schema))
.partition(|e| { .partition(|e| e.is_ok());
e.is_ok()
});
for err in invalid_cand.iter() { for err in invalid_cand.iter() {
audit_log!(au, "Schema Violation: {:?}", err); audit_log!(au, "Schema Violation: {:?}", err);
@ -279,14 +286,11 @@ impl<'a> QueryServerWriteTransaction<'a> {
return Err(OperationError::SchemaViolation); return Err(OperationError::SchemaViolation);
} }
let norm_cand: Vec<Entry<EntryValid, EntryNew>> = norm_cand.into_iter() let norm_cand: Vec<Entry<EntryValid, EntryNew>> = norm_cand
.map(|e| { .into_iter()
match e { .map(|e| match e {
Ok(v) => v, Ok(v) => v,
Err(_) => { Err(_) => panic!("Invalid data set state!!!"),
panic!("Invalid data set state!!!")
}
}
}) })
.collect(); .collect();
@ -319,7 +323,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
res res
} }
pub fn delete(&self, au: &mut AuditScope, ce: &DeleteEvent) -> Result<(), OperationError> { pub fn delete(&self, au: &mut AuditScope, ce: &DeleteEvent) -> Result<(), OperationError> {
unimplemented!() unimplemented!()
} }
@ -340,19 +343,17 @@ impl<'a> QueryServerWriteTransaction<'a> {
}; };
if pre_candidates.len() == 0 { if pre_candidates.len() == 0 {
return Err(OperationError::NoMatchingEntries) return Err(OperationError::NoMatchingEntries);
}; };
// Clone a set of writeables. // Clone a set of writeables.
// Apply the modlist -> Remember, we have a set of origs // Apply the modlist -> Remember, we have a set of origs
// and the new modified ents. // and the new modified ents.
let mut candidates: Vec<Entry<EntryInvalid, EntryCommitted>> = pre_candidates.into_iter() let mut candidates: Vec<Entry<EntryInvalid, EntryCommitted>> = pre_candidates
.into_iter()
.map(|er| { .map(|er| {
// TODO: Deal with this properly william // TODO: Deal with this properly william
er er.invalidate().apply_modlist(&me.modlist).unwrap()
.invalidate()
.apply_modlist(&me.modlist)
.unwrap()
}) })
.collect(); .collect();
@ -364,15 +365,13 @@ impl<'a> QueryServerWriteTransaction<'a> {
// FIXME: This normalisation COPIES everything, which may be // FIXME: This normalisation COPIES everything, which may be
// slow. // slow.
let (norm_cand, invalid_cand): let (norm_cand, invalid_cand): (
(Vec<Result<Entry<EntryValid, EntryCommitted>, _>>, Vec<Result<Entry<EntryValid, EntryCommitted>, _>>,
Vec<Result<_, SchemaError>>) = candidates.into_iter() Vec<Result<_, SchemaError>>,
.map(|e| { ) = candidates
e.validate(&self.schema) .into_iter()
}) .map(|e| e.validate(&self.schema))
.partition(|e| { .partition(|e| e.is_ok());
e.is_ok()
});
for err in invalid_cand.iter() { for err in invalid_cand.iter() {
audit_log!(au, "Schema Violation: {:?}", err); audit_log!(au, "Schema Violation: {:?}", err);
@ -382,14 +381,11 @@ impl<'a> QueryServerWriteTransaction<'a> {
return Err(OperationError::SchemaViolation); return Err(OperationError::SchemaViolation);
} }
let norm_cand: Vec<Entry<EntryValid, EntryCommitted>> = norm_cand.into_iter() let norm_cand: Vec<Entry<EntryValid, EntryCommitted>> = norm_cand
.map(|e| { .into_iter()
match e { .map(|e| match e {
Ok(v) => v, Ok(v) => v,
Err(_) => { Err(_) => panic!("Invalid data set state!!!"),
panic!("Invalid data set state!!!")
}
}
}) })
.collect(); .collect();
@ -442,7 +438,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
pub fn internal_delete( pub fn internal_delete(
&self, &self,
audit: &mut AuditScope, audit: &mut AuditScope,
filter: Filter filter: Filter,
) -> Result<(), OperationError> { ) -> Result<(), OperationError> {
let mut audit_int = AuditScope::new("internal_delete"); let mut audit_int = AuditScope::new("internal_delete");
let de = DeleteEvent::new_internal(filter); let de = DeleteEvent::new_internal(filter);
@ -455,7 +451,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
&self, &self,
audit: &mut AuditScope, audit: &mut AuditScope,
filter: Filter, filter: Filter,
modlist: ModifyList modlist: ModifyList,
) -> Result<(), OperationError> { ) -> Result<(), OperationError> {
let mut audit_int = AuditScope::new("internal_modify"); let mut audit_int = AuditScope::new("internal_modify");
let me = ModifyEvent::new_internal(filter, modlist); let me = ModifyEvent::new_internal(filter, modlist);
@ -470,7 +466,10 @@ impl<'a> QueryServerWriteTransaction<'a> {
// and markers. They act as though they have the highest level privilege // and markers. They act as though they have the highest level privilege
// IE there are no access control checks. // IE there are no access control checks.
pub fn internal_exists_or_create(&self, e: Entry<EntryValid, EntryNew>) -> Result<(), OperationError> { pub fn internal_exists_or_create(
&self,
e: Entry<EntryValid, EntryNew>,
) -> Result<(), OperationError> {
// If the thing exists, stop. // If the thing exists, stop.
// if not, create from Entry. // if not, create from Entry.
unimplemented!() unimplemented!()
@ -549,9 +548,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
self.internal_create(audit, vec![e.invalidate()]) self.internal_create(audit, vec![e.invalidate()])
} else if results.len() == 1 { } else if results.len() == 1 {
// it exists. To guarantee content exactly as is, we compare if it's identical. // it exists. To guarantee content exactly as is, we compare if it's identical.
audit_log!(audit, "LEFT -> {:?}", &e);
audit_log!(audit, "RIGHT -> {:?}", &results[0]);
if !e.compare(&results[0]) { if !e.compare(&results[0]) {
self.internal_delete(audit, filt); self.internal_delete(audit, filt);
self.internal_create(audit, vec![e.invalidate()]); self.internal_create(audit, vec![e.invalidate()]);
@ -715,7 +711,7 @@ mod tests {
use super::super::audit::AuditScope; use super::super::audit::AuditScope;
use super::super::be::{Backend, BackendTransaction}; use super::super::be::{Backend, BackendTransaction};
use super::super::entry::{Entry, EntryNew, EntryCommitted, EntryValid, EntryInvalid}; use super::super::entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
use super::super::event::{CreateEvent, SearchEvent}; use super::super::event::{CreateEvent, SearchEvent};
use super::super::filter::Filter; use super::super::filter::Filter;
use super::super::log; use super::super::log;
@ -791,9 +787,7 @@ mod tests {
println!("--> {:?}", r2); println!("--> {:?}", r2);
assert!(r2.len() == 1); assert!(r2.len() == 1);
let expected = unsafe { let expected = unsafe { vec![e.to_valid_committed()] };
vec![e.to_valid_committed()]
};
assert_eq!(r2, expected); assert_eq!(r2, expected);