mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
cargo fmt
This commit is contained in:
parent
66e087787a
commit
63e600d49e
|
@ -8,7 +8,7 @@ use serde_json;
|
|||
// use uuid;
|
||||
|
||||
use audit::AuditScope;
|
||||
use entry::{Entry, EntryValid, EntryNew, EntryCommitted};
|
||||
use entry::{Entry, EntryCommitted, EntryNew, EntryValid};
|
||||
use filter::Filter;
|
||||
|
||||
mod idl;
|
||||
|
@ -53,7 +53,11 @@ pub trait BackendReadTransaction {
|
|||
fn get_conn(&self) -> &r2d2::PooledConnection<r2d2_sqlite::SqliteConnectionManager>;
|
||||
|
||||
// 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
|
||||
// Alloc a vec for the entries.
|
||||
// FIXME: Make this actually a good size for the result set ...
|
||||
|
@ -97,7 +101,8 @@ pub trait BackendReadTransaction {
|
|||
.iter()
|
||||
.filter_map(|id_ent| {
|
||||
// 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);
|
||||
if e.entry_match_no_index(&filt) {
|
||||
Some(e)
|
||||
|
@ -206,10 +211,14 @@ impl BackendWriteTransaction {
|
|||
}
|
||||
|
||||
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());
|
||||
|
||||
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");
|
||||
match i {
|
||||
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, || {
|
||||
// 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() {
|
||||
// TODO: Better error
|
||||
return Err(BackendError::EmptyRequest);
|
||||
|
@ -291,7 +308,7 @@ impl BackendWriteTransaction {
|
|||
data: serde_json::to_string(&e).unwrap(),
|
||||
})
|
||||
}
|
||||
None => None
|
||||
None => None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
@ -307,20 +324,25 @@ impl BackendWriteTransaction {
|
|||
// Now, given the list of id's, update them
|
||||
{
|
||||
// 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| {
|
||||
stmt.execute_named(&[
|
||||
(":id", &ser_ent.id),
|
||||
(":data", &ser_ent.data),
|
||||
]).unwrap();
|
||||
stmt.execute_named(&[(":id", &ser_ent.id), (":data", &ser_ent.data)])
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
if entries.is_empty() {
|
||||
|
@ -329,11 +351,7 @@ impl BackendWriteTransaction {
|
|||
}
|
||||
|
||||
// Assert the Id's exist on the entry.
|
||||
let id_list: Vec<i64> = entries.iter()
|
||||
.filter_map(|entry| {
|
||||
entry.id
|
||||
})
|
||||
.collect();
|
||||
let id_list: Vec<i64> = entries.iter().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
|
||||
// TODO: This check won't be needed once I rebuild the entry state types.
|
||||
|
@ -348,7 +366,10 @@ impl BackendWriteTransaction {
|
|||
// probably okay with this.
|
||||
|
||||
// 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| {
|
||||
stmt.execute(&[id]).unwrap();
|
||||
|
@ -532,7 +553,7 @@ mod tests {
|
|||
extern crate tokio;
|
||||
|
||||
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::{
|
||||
Backend, BackendError, BackendReadTransaction, BackendTransaction, BackendWriteTransaction,
|
||||
|
@ -560,7 +581,7 @@ mod tests {
|
|||
let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap();
|
||||
let entries = $be.search($audit, &filt).unwrap();
|
||||
entries.first().is_some()
|
||||
}}
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! entry_attr_pres {
|
||||
|
@ -569,12 +590,10 @@ mod tests {
|
|||
let filt = ei.filter_from_attrs(&vec![String::from("userid")]).unwrap();
|
||||
let entries = $be.search($audit, &filt).unwrap();
|
||||
match entries.first() {
|
||||
Some(ent) => {
|
||||
ent.attribute_pres($attr)
|
||||
Some(ent) => ent.attribute_pres($attr),
|
||||
None => false,
|
||||
}
|
||||
None => false
|
||||
}
|
||||
}}
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -625,7 +644,9 @@ mod tests {
|
|||
assert!(entry_exists!(audit, be, e2));
|
||||
|
||||
// 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.
|
||||
let r1 = results.remove(0);
|
||||
|
@ -689,9 +710,10 @@ mod tests {
|
|||
assert!(entry_exists!(audit, be, e2));
|
||||
assert!(entry_exists!(audit, be, e3));
|
||||
|
||||
|
||||
// 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.
|
||||
let r1 = results.remove(0);
|
||||
|
@ -727,7 +749,6 @@ mod tests {
|
|||
// delete none (no entries left)
|
||||
// see fn delete for why this is ok, not err
|
||||
assert!(be.delete(audit, &vec![r2.clone(), r3.clone()]).is_ok());
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
108
src/lib/entry.rs
108
src/lib/entry.rs
|
@ -1,14 +1,14 @@
|
|||
// use serde_json::{Error, Value};
|
||||
use super::proto_v1::Entry as ProtoEntry;
|
||||
use error::SchemaError;
|
||||
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::BTreeMap;
|
||||
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::slice::Iter as SliceIter;
|
||||
|
||||
// make a trait entry for everything to adhere to?
|
||||
// * How to get indexs out?
|
||||
|
@ -175,10 +175,18 @@ impl Entry<EntryInvalid, EntryNew> {
|
|||
}
|
||||
|
||||
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 destructure:
|
||||
let Entry { valid, state, id, attrs } = self;
|
||||
let Entry {
|
||||
valid,
|
||||
state,
|
||||
id,
|
||||
attrs,
|
||||
} = self;
|
||||
|
||||
let schema_classes = schema.get_classes();
|
||||
let schema_attributes = schema.get_attributes();
|
||||
|
@ -232,20 +240,16 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
|||
{
|
||||
// First, check we have class on the object ....
|
||||
if !ne.attribute_pres("class") {
|
||||
return Err(SchemaError::InvalidClass)
|
||||
return Err(SchemaError::InvalidClass);
|
||||
}
|
||||
|
||||
let entry_classes = ne.classes();
|
||||
let entry_classes_size = entry_classes.len();
|
||||
|
||||
let classes: HashMap<String, &SchemaClass> = entry_classes
|
||||
.filter_map(|c| {
|
||||
match schema_classes.get(c) {
|
||||
Some(cls) => {
|
||||
Some((c.clone(), cls))
|
||||
}
|
||||
.filter_map(|c| match schema_classes.get(c) {
|
||||
Some(cls) => Some((c.clone(), cls)),
|
||||
None => None,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -253,7 +257,6 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
|||
return Err(SchemaError::InvalidClass);
|
||||
};
|
||||
|
||||
|
||||
let extensible = classes.contains_key("extensibleobject");
|
||||
|
||||
// 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 {
|
||||
let avas = ne.get_ava(&attr_name);
|
||||
if avas.is_none() {
|
||||
return Err(SchemaError::MissingMustAttribute(
|
||||
String::from(attr_name)
|
||||
));
|
||||
return Err(SchemaError::MissingMustAttribute(String::from(attr_name)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,7 +305,7 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
|||
// We have to destructure here to make type checker happy
|
||||
match r {
|
||||
Ok(_) => {}
|
||||
Err(e) => return Err(e)
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
}
|
||||
None => {
|
||||
|
@ -322,7 +323,8 @@ impl<STATE> Entry<EntryInvalid, STATE> {
|
|||
}
|
||||
|
||||
impl<VALID, STATE> Clone for Entry<VALID, STATE>
|
||||
where VALID: Copy,
|
||||
where
|
||||
VALID: Copy,
|
||||
STATE: Copy,
|
||||
{
|
||||
// Dirty modifiable state. Works on any other state to dirty them.
|
||||
|
@ -381,7 +383,7 @@ impl<STATE> Entry<EntryValid, STATE> {
|
|||
valid: EntryInvalid,
|
||||
state: self.state,
|
||||
id: self.id,
|
||||
attrs: self.attrs
|
||||
attrs: self.attrs,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,7 +392,7 @@ impl<STATE> Entry<EntryValid, STATE> {
|
|||
valid: self.valid,
|
||||
state: EntryCommitted,
|
||||
id: self.id,
|
||||
attrs: self.attrs
|
||||
attrs: self.attrs,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -400,34 +402,28 @@ impl<STATE> Entry<EntryValid, STATE> {
|
|||
// This is recursive!!!!
|
||||
match filter {
|
||||
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) => {
|
||||
// Given attr, is is present in the entry?
|
||||
self.attribute_pres(attr.as_str())
|
||||
}
|
||||
Filter::Or(l) => {
|
||||
l.iter()
|
||||
.fold(false, |acc, f| {
|
||||
Filter::Or(l) => l.iter().fold(false, |acc, f| {
|
||||
if acc {
|
||||
acc
|
||||
} else {
|
||||
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 {
|
||||
self.entry_match_no_index(f)
|
||||
} else {
|
||||
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
|
||||
// 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.
|
||||
|
@ -490,9 +485,7 @@ impl<STATE> Entry<EntryValid, STATE> {
|
|||
mods.push_mod(Modify::Purged(k.clone()));
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(())
|
||||
}
|
||||
Err(e) => return Err(()),
|
||||
}
|
||||
for v in vs {
|
||||
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?
|
||||
// How do we indicate "empty?"
|
||||
// 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());
|
||||
EntryClasses { size: v, inner: c }
|
||||
}
|
||||
|
@ -548,7 +545,8 @@ impl<VALID, STATE> Entry<VALID, 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
|
||||
// a list of syntax violations ...
|
||||
|
@ -589,8 +587,7 @@ impl<STATE> Entry<EntryInvalid, STATE>
|
|||
v.remove(idx);
|
||||
}
|
||||
// It does not exist, move on.
|
||||
Err(_) => {
|
||||
}
|
||||
Err(_) => {}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -618,8 +615,7 @@ impl<STATE> Entry<EntryInvalid, STATE>
|
|||
// This is effectively clone-and-transform
|
||||
|
||||
// clone the entry
|
||||
let mut ne: Entry<EntryInvalid, STATE> =
|
||||
Entry {
|
||||
let mut ne: Entry<EntryInvalid, STATE> = Entry {
|
||||
valid: self.valid,
|
||||
state: self.state,
|
||||
id: self.id,
|
||||
|
@ -629,15 +625,9 @@ impl<STATE> Entry<EntryInvalid, STATE>
|
|||
// mutate
|
||||
for modify in modlist.mods.iter() {
|
||||
match modify {
|
||||
Modify::Present(a, v) => {
|
||||
ne.add_ava(a.clone(), v.clone())
|
||||
}
|
||||
Modify::Removed(a, v) => {
|
||||
ne.remove_ava(a, v)
|
||||
}
|
||||
Modify::Purged(a) => {
|
||||
ne.purge_ava(a)
|
||||
}
|
||||
Modify::Present(a, v) => ne.add_ava(a.clone(), v.clone()),
|
||||
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();
|
||||
e.add_ava(String::from("userid"), String::from("william"));
|
||||
|
||||
let mods = ModifyList::new_list(vec![
|
||||
Modify::Present(String::from("attr"), String::from("value")),
|
||||
]);
|
||||
let mods = ModifyList::new_list(vec![Modify::Present(
|
||||
String::from("attr"),
|
||||
String::from("value"),
|
||||
)]);
|
||||
|
||||
let ne = e.apply_modlist(&mods).unwrap();
|
||||
|
||||
// Assert the changes are there
|
||||
assert!(ne.attribute_equality("attr", "value"));
|
||||
|
||||
|
||||
// Assert present for multivalue
|
||||
// Assert purge on single/multi/empty value
|
||||
// Assert removed on value that exists and doesn't exist
|
||||
|
|
|
@ -2,7 +2,7 @@ use super::filter::Filter;
|
|||
use super::proto_v1::Entry as ProtoEntry;
|
||||
use super::proto_v1::{CreateRequest, Response, SearchRequest, SearchResponse};
|
||||
use actix::prelude::*;
|
||||
use entry::{Entry, EntryInvalid, EntryNew, EntryValid, EntryCommitted};
|
||||
use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
|
||||
use error::OperationError;
|
||||
use modify::ModifyList;
|
||||
|
||||
|
@ -185,4 +185,3 @@ impl ModifyEvent {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// in parallel map/reduce style, or directly on a single
|
||||
// entry to assert it matches.
|
||||
|
||||
use std::cmp::{Ordering, PartialOrd};
|
||||
use regex::Regex;
|
||||
use std::cmp::{Ordering, PartialOrd};
|
||||
|
||||
// Perhaps make these json serialisable. Certainly would make parsing
|
||||
// simpler ...
|
||||
|
@ -102,7 +102,7 @@ impl PartialOrd for Filter {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::Filter;
|
||||
use entry::{Entry, EntryValid, EntryNew};
|
||||
use entry::{Entry, EntryNew, EntryValid};
|
||||
use serde_json;
|
||||
use std::cmp::{Ordering, PartialOrd};
|
||||
|
||||
|
@ -199,14 +199,17 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"userid": ["william"],
|
||||
"uidNumber": ["1000"]
|
||||
}
|
||||
}"#).unwrap();
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let f_t1a = Filter::Or(vec![
|
||||
Filter::Eq(String::from("userid"), String::from("william")),
|
||||
|
@ -235,14 +238,17 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"userid": ["william"],
|
||||
"uidNumber": ["1000"]
|
||||
}
|
||||
}"#).unwrap();
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let f_t1a = Filter::And(vec![
|
||||
Filter::Eq(String::from("userid"), String::from("william")),
|
||||
|
@ -271,64 +277,80 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
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,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"userid": ["william"],
|
||||
"uidNumber": ["1000"]
|
||||
}
|
||||
}"#).unwrap();
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let f_t1a = Filter::Not(Box::new(
|
||||
Filter::Eq(String::from("userid"), String::from("alice")),
|
||||
));
|
||||
let f_t1a = Filter::Not(Box::new(Filter::Eq(
|
||||
String::from("userid"),
|
||||
String::from("alice"),
|
||||
)));
|
||||
assert!(e1.entry_match_no_index(&f_t1a));
|
||||
|
||||
let f_t2a = Filter::Not(Box::new(
|
||||
Filter::Eq(String::from("userid"), String::from("william")),
|
||||
));
|
||||
let f_t2a = Filter::Not(Box::new(Filter::Eq(
|
||||
String::from("userid"),
|
||||
String::from("william"),
|
||||
)));
|
||||
assert!(!e1.entry_match_no_index(&f_t2a));
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
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,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"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,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"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,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"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,
|
||||
"state": null,
|
||||
"attrs": {
|
||||
"class": ["group"],
|
||||
"uidNumber": ["1000"]
|
||||
}
|
||||
}"#).unwrap();
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let f_t1a = Filter::And(vec![
|
||||
Filter::Eq(String::from("class"), String::from("person")),
|
||||
|
|
|
@ -39,10 +39,10 @@ mod constants;
|
|||
mod entry;
|
||||
mod event;
|
||||
mod identity;
|
||||
mod modify;
|
||||
mod plugins;
|
||||
mod schema;
|
||||
mod server;
|
||||
mod modify;
|
||||
|
||||
pub mod config;
|
||||
pub mod core;
|
||||
|
|
|
@ -133,7 +133,7 @@ mod tests {
|
|||
|
||||
use audit::AuditScope;
|
||||
use be::{Backend, BackendWriteTransaction};
|
||||
use entry::{Entry, EntryValid, EntryInvalid, EntryNew};
|
||||
use entry::{Entry, EntryInvalid, EntryNew, EntryValid};
|
||||
use event::CreateEvent;
|
||||
use schema::{Schema, SchemaWriteTransaction};
|
||||
|
||||
|
|
|
@ -75,3 +75,23 @@ impl CreateRequest {
|
|||
//
|
||||
// On loginSuccess, we send a cookie, and that allows the token to be
|
||||
// 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 {}
|
||||
|
|
|
@ -5,11 +5,11 @@ use super::error::SchemaError;
|
|||
use super::filter::Filter;
|
||||
use std::collections::HashMap;
|
||||
// Apparently this is nightly only?
|
||||
use modify::ModifyList;
|
||||
use regex::Regex;
|
||||
use std::convert::TryFrom;
|
||||
use std::str::FromStr;
|
||||
use uuid::Uuid;
|
||||
use modify::ModifyList;
|
||||
|
||||
use concread::cowcell::{CowCell, CowCellReadTxn, CowCellWriteTxn};
|
||||
|
||||
|
@ -917,9 +917,7 @@ impl SchemaInner {
|
|||
}
|
||||
})
|
||||
}
|
||||
Filter::Not(filter) => {
|
||||
self.validate_filter(filter)
|
||||
}
|
||||
Filter::Not(filter) => self.validate_filter(filter),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -932,9 +930,7 @@ impl SchemaInner {
|
|||
|
||||
fn is_multivalue(&self, attr_name: &str) -> Result<bool, SchemaError> {
|
||||
match self.attributes.get(attr_name) {
|
||||
Some(a_schema) => {
|
||||
Ok(a_schema.multivalue)
|
||||
}
|
||||
Some(a_schema) => Ok(a_schema.multivalue),
|
||||
None => {
|
||||
return Err(SchemaError::InvalidAttribute);
|
||||
}
|
||||
|
@ -1009,7 +1005,7 @@ impl Schema {
|
|||
mod tests {
|
||||
use super::super::audit::AuditScope;
|
||||
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::filter::Filter;
|
||||
use super::{IndexType, Schema, SchemaAttribute, SchemaClass, SyntaxType};
|
||||
|
@ -1238,10 +1234,7 @@ mod tests {
|
|||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
e_no_class.validate(&schema),
|
||||
Err(SchemaError::InvalidClass)
|
||||
);
|
||||
assert_eq!(e_no_class.validate(&schema), Err(SchemaError::InvalidClass));
|
||||
|
||||
let e_bad_class: Entry<EntryInvalid, EntryNew> = serde_json::from_str(
|
||||
r#"{
|
||||
|
|
|
@ -10,15 +10,16 @@ use be::{
|
|||
};
|
||||
|
||||
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 event::{CreateEvent, ExistsEvent, OpResult, SearchEvent, SearchResult, DeleteEvent, ModifyEvent};
|
||||
use event::{
|
||||
CreateEvent, DeleteEvent, ExistsEvent, ModifyEvent, OpResult, SearchEvent, SearchResult,
|
||||
};
|
||||
use filter::Filter;
|
||||
use log::EventLog;
|
||||
use plugins::Plugins;
|
||||
use schema::{Schema, SchemaTransaction, SchemaReadTransaction, SchemaWriteTransaction};
|
||||
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> {
|
||||
let mut audit = AuditScope::new("server_start");
|
||||
|
@ -89,7 +90,11 @@ pub trait QueryServerReadTransaction {
|
|||
|
||||
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
|
||||
// This is an important security step because it prevents us from
|
||||
// performing un-indexed searches on attr's that don't exist in the
|
||||
|
@ -141,8 +146,11 @@ pub trait QueryServerReadTransaction {
|
|||
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 se = SearchEvent::new_internal(filter);
|
||||
let res = self.search(&mut audit_int, &se);
|
||||
|
@ -240,7 +248,8 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
// based on request size in the frontend?
|
||||
|
||||
// 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.
|
||||
// pre-plugins are defined here in their correct order of calling!
|
||||
|
@ -261,15 +270,13 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
return plug_pre_res;
|
||||
}
|
||||
|
||||
let (norm_cand, invalid_cand):
|
||||
(Vec<Result<Entry<EntryValid, EntryNew>, _>>,
|
||||
Vec<Result<_, SchemaError>>) = candidates.into_iter()
|
||||
.map(|e| {
|
||||
e.validate(&self.schema)
|
||||
})
|
||||
.partition(|e| {
|
||||
e.is_ok()
|
||||
});
|
||||
let (norm_cand, invalid_cand): (
|
||||
Vec<Result<Entry<EntryValid, EntryNew>, _>>,
|
||||
Vec<Result<_, SchemaError>>,
|
||||
) = candidates
|
||||
.into_iter()
|
||||
.map(|e| e.validate(&self.schema))
|
||||
.partition(|e| e.is_ok());
|
||||
|
||||
for err in invalid_cand.iter() {
|
||||
audit_log!(au, "Schema Violation: {:?}", err);
|
||||
|
@ -279,14 +286,11 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
return Err(OperationError::SchemaViolation);
|
||||
}
|
||||
|
||||
let norm_cand: Vec<Entry<EntryValid, EntryNew>> = norm_cand.into_iter()
|
||||
.map(|e| {
|
||||
match e {
|
||||
let norm_cand: Vec<Entry<EntryValid, EntryNew>> = norm_cand
|
||||
.into_iter()
|
||||
.map(|e| match e {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
panic!("Invalid data set state!!!")
|
||||
}
|
||||
}
|
||||
Err(_) => panic!("Invalid data set state!!!"),
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -319,7 +323,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
res
|
||||
}
|
||||
|
||||
|
||||
pub fn delete(&self, au: &mut AuditScope, ce: &DeleteEvent) -> Result<(), OperationError> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
@ -340,19 +343,17 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
};
|
||||
|
||||
if pre_candidates.len() == 0 {
|
||||
return Err(OperationError::NoMatchingEntries)
|
||||
return Err(OperationError::NoMatchingEntries);
|
||||
};
|
||||
|
||||
// Clone a set of writeables.
|
||||
// Apply the modlist -> Remember, we have a set of origs
|
||||
// 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| {
|
||||
// TODO: Deal with this properly william
|
||||
er
|
||||
.invalidate()
|
||||
.apply_modlist(&me.modlist)
|
||||
.unwrap()
|
||||
er.invalidate().apply_modlist(&me.modlist).unwrap()
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -364,15 +365,13 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
// FIXME: This normalisation COPIES everything, which may be
|
||||
// slow.
|
||||
|
||||
let (norm_cand, invalid_cand):
|
||||
(Vec<Result<Entry<EntryValid, EntryCommitted>, _>>,
|
||||
Vec<Result<_, SchemaError>>) = candidates.into_iter()
|
||||
.map(|e| {
|
||||
e.validate(&self.schema)
|
||||
})
|
||||
.partition(|e| {
|
||||
e.is_ok()
|
||||
});
|
||||
let (norm_cand, invalid_cand): (
|
||||
Vec<Result<Entry<EntryValid, EntryCommitted>, _>>,
|
||||
Vec<Result<_, SchemaError>>,
|
||||
) = candidates
|
||||
.into_iter()
|
||||
.map(|e| e.validate(&self.schema))
|
||||
.partition(|e| e.is_ok());
|
||||
|
||||
for err in invalid_cand.iter() {
|
||||
audit_log!(au, "Schema Violation: {:?}", err);
|
||||
|
@ -382,14 +381,11 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
return Err(OperationError::SchemaViolation);
|
||||
}
|
||||
|
||||
let norm_cand: Vec<Entry<EntryValid, EntryCommitted>> = norm_cand.into_iter()
|
||||
.map(|e| {
|
||||
match e {
|
||||
let norm_cand: Vec<Entry<EntryValid, EntryCommitted>> = norm_cand
|
||||
.into_iter()
|
||||
.map(|e| match e {
|
||||
Ok(v) => v,
|
||||
Err(_) => {
|
||||
panic!("Invalid data set state!!!")
|
||||
}
|
||||
}
|
||||
Err(_) => panic!("Invalid data set state!!!"),
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
@ -442,7 +438,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
pub fn internal_delete(
|
||||
&self,
|
||||
audit: &mut AuditScope,
|
||||
filter: Filter
|
||||
filter: Filter,
|
||||
) -> Result<(), OperationError> {
|
||||
let mut audit_int = AuditScope::new("internal_delete");
|
||||
let de = DeleteEvent::new_internal(filter);
|
||||
|
@ -455,7 +451,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
&self,
|
||||
audit: &mut AuditScope,
|
||||
filter: Filter,
|
||||
modlist: ModifyList
|
||||
modlist: ModifyList,
|
||||
) -> Result<(), OperationError> {
|
||||
let mut audit_int = AuditScope::new("internal_modify");
|
||||
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
|
||||
// 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 not, create from Entry.
|
||||
unimplemented!()
|
||||
|
@ -549,9 +548,6 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
self.internal_create(audit, vec![e.invalidate()])
|
||||
} else if results.len() == 1 {
|
||||
// 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]) {
|
||||
self.internal_delete(audit, filt);
|
||||
self.internal_create(audit, vec![e.invalidate()]);
|
||||
|
@ -715,7 +711,7 @@ mod tests {
|
|||
|
||||
use super::super::audit::AuditScope;
|
||||
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::filter::Filter;
|
||||
use super::super::log;
|
||||
|
@ -791,9 +787,7 @@ mod tests {
|
|||
println!("--> {:?}", r2);
|
||||
assert!(r2.len() == 1);
|
||||
|
||||
let expected = unsafe {
|
||||
vec![e.to_valid_committed()]
|
||||
};
|
||||
let expected = unsafe { vec![e.to_valid_committed()] };
|
||||
|
||||
assert_eq!(r2, expected);
|
||||
|
||||
|
|
Loading…
Reference in a new issue