mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-24 04:57:00 +01:00
Most changes for state validated modlist done, just need to write the validate!
This commit is contained in:
parent
108a097bd0
commit
658e409d90
|
@ -2,7 +2,7 @@
|
||||||
use super::proto_v1::Entry as ProtoEntry;
|
use super::proto_v1::Entry as ProtoEntry;
|
||||||
use error::SchemaError;
|
use error::SchemaError;
|
||||||
use filter::{Filter, FilterValid};
|
use filter::{Filter, FilterValid};
|
||||||
use modify::{Modify, ModifyList};
|
use modify::{Modify, ModifyList, ModifyValid, ModifyInvalid};
|
||||||
use schema::{SchemaAttribute, SchemaClass, SchemaReadTransaction};
|
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;
|
||||||
|
@ -503,7 +503,7 @@ impl<STATE> Entry<EntryValid, STATE> {
|
||||||
pub fn gen_modlist_assert(
|
pub fn gen_modlist_assert(
|
||||||
&self,
|
&self,
|
||||||
schema: &SchemaReadTransaction,
|
schema: &SchemaReadTransaction,
|
||||||
) -> Result<ModifyList, SchemaError> {
|
) -> Result<ModifyList<ModifyInvalid>, SchemaError> {
|
||||||
// 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.
|
||||||
|
@ -645,7 +645,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should this be schemaless, relying on checks of the modlist, and the entry validate after?
|
// Should this be schemaless, relying on checks of the modlist, and the entry validate after?
|
||||||
pub fn apply_modlist(&self, modlist: &ModifyList) -> Result<Entry<EntryInvalid, STATE>, ()> {
|
pub fn apply_modlist(&self, modlist: &ModifyList<ModifyValid>) -> Result<Entry<EntryInvalid, STATE>, ()> {
|
||||||
// Apply a modlist, generating a new entry that conforms to the changes.
|
// Apply a modlist, generating a new entry that conforms to the changes.
|
||||||
// This is effectively clone-and-transform
|
// This is effectively clone-and-transform
|
||||||
|
|
||||||
|
@ -658,7 +658,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
// mutate
|
// mutate
|
||||||
for modify in modlist.mods.iter() {
|
for modify in modlist {
|
||||||
match modify {
|
match modify {
|
||||||
Modify::Present(a, v) => ne.add_ava(a.clone(), v.clone()),
|
Modify::Present(a, v) => ne.add_ava(a.clone(), v.clone()),
|
||||||
Modify::Removed(a, v) => ne.remove_ava(a, v),
|
Modify::Removed(a, v) => ne.remove_ava(a, v),
|
||||||
|
@ -770,10 +770,12 @@ 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![Modify::Present(
|
let mods = unsafe {
|
||||||
|
ModifyList::new_valid_list(vec![Modify::Present(
|
||||||
String::from("attr"),
|
String::from("attr"),
|
||||||
String::from("value"),
|
String::from("value"),
|
||||||
)]);
|
)])
|
||||||
|
};
|
||||||
|
|
||||||
let ne = e.apply_modlist(&mods).unwrap();
|
let ne = e.apply_modlist(&mods).unwrap();
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use super::proto_v1::{
|
||||||
};
|
};
|
||||||
use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
|
use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
|
||||||
// use error::OperationError;
|
// use error::OperationError;
|
||||||
use modify::ModifyList;
|
use modify::{ModifyList, ModifyInvalid};
|
||||||
|
|
||||||
use actix::prelude::*;
|
use actix::prelude::*;
|
||||||
|
|
||||||
|
@ -189,7 +189,7 @@ impl DeleteEvent {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ModifyEvent {
|
pub struct ModifyEvent {
|
||||||
pub filter: Filter<FilterInvalid>,
|
pub filter: Filter<FilterInvalid>,
|
||||||
pub modlist: ModifyList,
|
pub modlist: ModifyList<ModifyInvalid>,
|
||||||
pub internal: bool,
|
pub internal: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,7 +203,7 @@ impl ModifyEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn from_filter(filter: Filter<FilterInvalid>, modlist: ModifyList) -> Self {
|
pub fn from_filter(filter: Filter<FilterInvalid>, modlist: ModifyList<ModifyInvalid>) -> Self {
|
||||||
ModifyEvent {
|
ModifyEvent {
|
||||||
filter: filter,
|
filter: filter,
|
||||||
modlist: modlist,
|
modlist: modlist,
|
||||||
|
@ -211,7 +211,7 @@ impl ModifyEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_internal(filter: Filter<FilterInvalid>, modlist: ModifyList) -> Self {
|
pub fn new_internal(filter: Filter<FilterInvalid>, modlist: ModifyList<ModifyInvalid>) -> Self {
|
||||||
ModifyEvent {
|
ModifyEvent {
|
||||||
filter: filter,
|
filter: filter,
|
||||||
modlist: modlist,
|
modlist: modlist,
|
||||||
|
|
|
@ -1,6 +1,17 @@
|
||||||
use proto_v1::Modify as ProtoModify;
|
use proto_v1::Modify as ProtoModify;
|
||||||
use proto_v1::ModifyList as ProtoModifyList;
|
use proto_v1::ModifyList as ProtoModifyList;
|
||||||
|
|
||||||
|
use error::SchemaError;
|
||||||
|
use schema::{SchemaAttribute, SchemaReadTransaction};
|
||||||
|
|
||||||
|
// Should this be std?
|
||||||
|
use std::slice;
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ModifyValid;
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct ModifyInvalid;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub enum Modify {
|
pub enum Modify {
|
||||||
// This value *should* exist.
|
// This value *should* exist.
|
||||||
|
@ -22,36 +33,79 @@ impl Modify {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct ModifyList {
|
pub struct ModifyList<VALID> {
|
||||||
// And ordered list of changes to apply. Should this be state based?
|
valid: VALID,
|
||||||
pub mods: Vec<Modify>,
|
// The order of this list matters. Each change must be done in order.
|
||||||
|
mods: Vec<Modify>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: ModifyList should be like filter and have valid/invalid to schema.
|
// TODO: ModifyList should be like filter and have valid/invalid to schema.
|
||||||
// Or do we not care because the entry will be invalid at the end?
|
// Or do we not care because the entry will be invalid at the end?
|
||||||
|
|
||||||
impl ModifyList {
|
impl<'a> IntoIterator for &'a ModifyList<ModifyValid> {
|
||||||
|
type Item = &'a Modify;
|
||||||
|
type IntoIter = slice::Iter<'a, Modify>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.mods.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl ModifyList<ModifyInvalid> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ModifyList { mods: Vec::new() }
|
ModifyList {
|
||||||
|
valid: ModifyInvalid,
|
||||||
|
mods: Vec::new()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_list(mods: Vec<Modify>) -> Self {
|
pub fn new_list(mods: Vec<Modify>) -> Self {
|
||||||
ModifyList { mods: mods }
|
ModifyList {
|
||||||
|
valid: ModifyInvalid,
|
||||||
|
mods: mods
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn push_mod(&mut self, modify: Modify) {
|
pub fn push_mod(&mut self, modify: Modify) {
|
||||||
self.mods.push(modify)
|
self.mods.push(modify)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.mods.len()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from(ml: &ProtoModifyList) -> Self {
|
pub fn from(ml: &ProtoModifyList) -> Self {
|
||||||
// For each ProtoModify, do a from.
|
// For each ProtoModify, do a from.
|
||||||
|
|
||||||
ModifyList {
|
ModifyList {
|
||||||
|
valid: ModifyInvalid,
|
||||||
mods: ml.mods.iter().map(|pm| Modify::from(pm)).collect(),
|
mods: ml.mods.iter().map(|pm| Modify::from(pm)).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn validate(&self,
|
||||||
|
schema: &SchemaReadTransaction,
|
||||||
|
) -> Result<ModifyList<ModifyValid>, SchemaError> {
|
||||||
|
// Check that all attributes exist in the schema
|
||||||
|
|
||||||
|
// Normalise them
|
||||||
|
|
||||||
|
// Validate them
|
||||||
|
|
||||||
|
// Return new ModifyList!
|
||||||
|
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModifyList<ModifyValid> {
|
||||||
|
#[cfg(test)]
|
||||||
|
pub unsafe fn new_valid_list(mods: Vec<Modify>) -> Self {
|
||||||
|
ModifyList {
|
||||||
|
valid: ModifyValid,
|
||||||
|
mods: mods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<VALID> ModifyList<VALID> {
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.mods.len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use entry::{Entry, EntryCommitted, EntryInvalid, EntryNew, EntryValid};
|
||||||
use error::{OperationError, SchemaError};
|
use error::{OperationError, SchemaError};
|
||||||
use event::{CreateEvent, DeleteEvent, ExistsEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent};
|
use event::{CreateEvent, DeleteEvent, ExistsEvent, ModifyEvent, ReviveRecycledEvent, SearchEvent};
|
||||||
use filter::{Filter, FilterInvalid};
|
use filter::{Filter, FilterInvalid};
|
||||||
use modify::{Modify, ModifyList};
|
use modify::{Modify, ModifyList, ModifyInvalid};
|
||||||
use plugins::Plugins;
|
use plugins::Plugins;
|
||||||
use schema::{Schema, SchemaReadTransaction, SchemaTransaction, SchemaWriteTransaction};
|
use schema::{Schema, SchemaReadTransaction, SchemaTransaction, SchemaWriteTransaction};
|
||||||
|
|
||||||
|
@ -448,11 +448,16 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
return Err(OperationError::NoMatchingEntries);
|
return Err(OperationError::NoMatchingEntries);
|
||||||
};
|
};
|
||||||
|
|
||||||
let modlist = ModifyList::new_list(vec![Modify::Present(
|
let modlist_inv = ModifyList::new_list(vec![Modify::Present(
|
||||||
String::from("class"),
|
String::from("class"),
|
||||||
String::from("recycled"),
|
String::from("recycled"),
|
||||||
)]);
|
)]);
|
||||||
|
|
||||||
|
let modlist = match modlist_inv.validate(&self.schema) {
|
||||||
|
Ok(ml) => ml,
|
||||||
|
Err(e) => return Err(OperationError::SchemaViolation(e)),
|
||||||
|
};
|
||||||
|
|
||||||
let candidates: Vec<Entry<EntryInvalid, EntryCommitted>> = pre_candidates
|
let candidates: Vec<Entry<EntryInvalid, EntryCommitted>> = pre_candidates
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|er| {
|
.map(|er| {
|
||||||
|
@ -647,6 +652,12 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
return Err(OperationError::EmptyRequest);
|
return Err(OperationError::EmptyRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Is the modlist valid?
|
||||||
|
let modlist = match me.modlist.validate(&self.schema) {
|
||||||
|
Ok(ml) => ml,
|
||||||
|
Err(e) => return Err(OperationError::SchemaViolation(e)),
|
||||||
|
};
|
||||||
|
|
||||||
// Is the filter invalid to schema?
|
// Is the filter invalid to schema?
|
||||||
|
|
||||||
// WARNING! Check access controls here!!!!
|
// WARNING! Check access controls here!!!!
|
||||||
|
@ -675,7 +686,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|er| {
|
.map(|er| {
|
||||||
// TODO: Deal with this properly william
|
// TODO: Deal with this properly william
|
||||||
er.invalidate().apply_modlist(&me.modlist).unwrap()
|
er.invalidate().apply_modlist(&modlist).unwrap()
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -786,7 +797,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
&self,
|
&self,
|
||||||
audit: &mut AuditScope,
|
audit: &mut AuditScope,
|
||||||
filter: Filter<FilterInvalid>,
|
filter: Filter<FilterInvalid>,
|
||||||
modlist: ModifyList,
|
modlist: ModifyList<ModifyInvalid>,
|
||||||
) -> 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);
|
||||||
|
@ -799,7 +810,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
||||||
&self,
|
&self,
|
||||||
audit: &mut AuditScope,
|
audit: &mut AuditScope,
|
||||||
filter: Filter<FilterInvalid>,
|
filter: Filter<FilterInvalid>,
|
||||||
modlist: ModifyList,
|
modlist: ModifyList<ModifyInvalid>,
|
||||||
) -> Result<(), OperationError> {
|
) -> Result<(), OperationError> {
|
||||||
let mut audit_int = AuditScope::new("impersonate_modify");
|
let mut audit_int = AuditScope::new("impersonate_modify");
|
||||||
let me = ModifyEvent::new_internal(filter, modlist);
|
let me = ModifyEvent::new_internal(filter, modlist);
|
||||||
|
|
Loading…
Reference in a new issue