kanidm/kanidmd/src/lib/modify.rs

204 lines
5.7 KiB
Rust
Raw Normal View History

use crate::audit::AuditScope;
use kanidm_proto::v1::Modify as ProtoModify;
use kanidm_proto::v1::ModifyList as ProtoModifyList;
2019-02-22 07:15:48 +01:00
use crate::schema::SchemaTransaction;
use crate::server::{QueryServerTransaction, QueryServerWriteTransaction};
use crate::value::{PartialValue, Value};
use kanidm_proto::v1::{OperationError, SchemaError};
// Should this be std?
use std::slice;
#[derive(Serialize, Deserialize, Debug)]
pub struct ModifyValid;
#[derive(Serialize, Deserialize, Debug)]
pub struct ModifyInvalid;
#[derive(Debug)]
pub enum Modify {
// This value *should* exist.
Present(String, Value),
// This value *should not* exist.
Removed(String, PartialValue),
// This attr *should not* exist.
Purged(String),
}
#[allow(dead_code)]
pub fn m_pres(a: &str, v: &Value) -> Modify {
Modify::Present(a.to_string(), v.clone())
}
#[allow(dead_code)]
pub fn m_remove(a: &str, v: &PartialValue) -> Modify {
Modify::Removed(a.to_string(), v.clone())
}
#[allow(dead_code)]
pub fn m_purge(a: &str) -> Modify {
Modify::Purged(a.to_string())
}
2019-02-22 07:15:48 +01:00
impl Modify {
2019-03-20 06:30:34 +01:00
pub fn from(
audit: &mut AuditScope,
m: &ProtoModify,
2019-03-20 06:33:22 +01:00
qs: &QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
2019-03-17 04:24:06 +01:00
Ok(match m {
2019-03-20 06:30:34 +01:00
ProtoModify::Present(a, v) => Modify::Present(a.clone(), qs.clone_value(audit, a, v)?),
ProtoModify::Removed(a, v) => {
Modify::Removed(a.clone(), qs.clone_partialvalue(audit, a, v)?)
}
2019-02-24 05:15:37 +01:00
ProtoModify::Purged(a) => Modify::Purged(a.clone()),
2019-03-17 04:24:06 +01:00
})
2019-02-22 07:15:48 +01:00
}
}
#[derive(Debug)]
pub struct ModifyList<VALID> {
valid: VALID,
// The order of this list matters. Each change must be done in order.
mods: Vec<Modify>,
}
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 {
ModifyList {
valid: ModifyInvalid,
2019-03-12 06:40:25 +01:00
mods: Vec::new(),
}
}
pub fn new_list(mods: Vec<Modify>) -> Self {
ModifyList {
valid: ModifyInvalid,
2019-03-12 06:40:25 +01:00
mods: mods,
}
}
pub fn new_purge_and_set(attr: &str, v: Value) -> Self {
Self::new_list(vec![m_purge(attr), Modify::Present(attr.to_string(), v)])
}
pub fn new_purge(attr: &str) -> Self {
Self::new_list(vec![m_purge(attr)])
}
pub fn push_mod(&mut self, modify: Modify) {
self.mods.push(modify)
}
2019-03-17 04:24:06 +01:00
pub fn from(
2019-03-20 06:30:34 +01:00
audit: &mut AuditScope,
2019-03-17 04:24:06 +01:00
ml: &ProtoModifyList,
qs: &QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
2019-02-22 07:15:48 +01:00
// For each ProtoModify, do a from.
2019-03-20 06:33:22 +01:00
let inner: Result<Vec<_>, _> = ml
.mods
.iter()
.map(|pm| Modify::from(audit, pm, qs))
.collect();
2019-03-17 04:24:06 +01:00
match inner {
Ok(m) => Ok(ModifyList {
valid: ModifyInvalid,
mods: m,
}),
Err(e) => Err(e),
2019-02-22 07:15:48 +01:00
}
}
2019-03-12 06:40:25 +01:00
pub fn validate(
&self,
schema: &dyn SchemaTransaction,
2019-03-12 06:40:25 +01:00
) -> Result<ModifyList<ModifyValid>, SchemaError> {
let schema_attributes = schema.get_attributes();
/*
let schema_name = schema_attributes
.get("name")
.expect("Critical: Core schema corrupt or missing. To initiate a core transfer, please deposit substitute core in receptacle.");
*/
2019-03-12 06:40:25 +01:00
let res: Result<Vec<Modify>, _> = (&self.mods)
.into_iter()
.map(|m| match m {
Modify::Present(attr, value) => {
let attr_norm = schema.normalise_attr_name(attr);
2019-03-12 06:40:25 +01:00
match schema_attributes.get(&attr_norm) {
Some(schema_a) => schema_a
.validate_value(&value)
.map(|_| Modify::Present(attr_norm, value.clone())),
2019-03-12 06:40:25 +01:00
None => Err(SchemaError::InvalidAttribute),
}
2019-03-12 06:40:25 +01:00
}
Modify::Removed(attr, value) => {
let attr_norm = schema.normalise_attr_name(attr);
2019-03-12 06:40:25 +01:00
match schema_attributes.get(&attr_norm) {
Some(schema_a) => schema_a
.validate_partialvalue(&value)
.map(|_| Modify::Removed(attr_norm, value.clone())),
2019-03-12 06:40:25 +01:00
None => Err(SchemaError::InvalidAttribute),
}
2019-03-12 06:40:25 +01:00
}
Modify::Purged(attr) => {
let attr_norm = schema.normalise_attr_name(attr);
2019-03-12 06:40:25 +01:00
match schema_attributes.get(&attr_norm) {
Some(_attr_name) => Ok(Modify::Purged(attr_norm)),
None => Err(SchemaError::InvalidAttribute),
}
}
})
.collect();
let valid_mods = match res {
Ok(v) => v,
Err(e) => return Err(e),
};
// Return new ModifyList!
Ok(ModifyList {
valid: ModifyValid,
mods: valid_mods,
})
}
#[cfg(test)]
pub unsafe fn to_valid(self) -> ModifyList<ModifyValid> {
ModifyList {
valid: ModifyValid,
mods: self.mods,
}
}
}
impl ModifyList<ModifyValid> {
#[cfg(test)]
pub unsafe fn new_valid_list(mods: Vec<Modify>) -> Self {
ModifyList {
valid: ModifyValid,
2019-03-12 06:40:25 +01:00
mods: mods,
}
}
pub fn iter(&self) -> slice::Iter<Modify> {
self.mods.iter()
}
}
impl<VALID> ModifyList<VALID> {
pub fn len(&self) -> usize {
self.mods.len()
}
}