mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
Add plugin links,
This commit is contained in:
parent
b888d9036f
commit
db024258f2
|
@ -12,7 +12,7 @@ macro_rules! audit_log {
|
|||
($audit:expr, $($arg:tt)*) => ({
|
||||
use std::fmt;
|
||||
if cfg!(test) || cfg!(debug_assertions) {
|
||||
print!("DEBUG AUDIT -> ");
|
||||
print!("DEBUG AUDIT ({})-> ", $audit.id());
|
||||
println!($($arg)*)
|
||||
}
|
||||
$audit.log_event(
|
||||
|
@ -101,6 +101,10 @@ impl AuditScope {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> &str {
|
||||
self.name.as_str()
|
||||
}
|
||||
|
||||
// Given a new audit event, append it in.
|
||||
pub fn append_scope(&mut self, scope: AuditScope) {
|
||||
self.events.push(AuditEvent::scope(scope))
|
||||
|
|
|
@ -5,7 +5,11 @@ use error::OperationError;
|
|||
use event::CreateEvent;
|
||||
use schema::Schema;
|
||||
|
||||
mod uuid;
|
||||
|
||||
trait Plugin {
|
||||
fn id() -> &'static str;
|
||||
|
||||
fn pre_create(
|
||||
be: &mut Backend,
|
||||
au: &mut AuditScope,
|
||||
|
@ -45,7 +49,48 @@ trait Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
mod uuid;
|
||||
pub struct Plugins{}
|
||||
|
||||
macro_rules! run_pre_create_plugin {
|
||||
(
|
||||
$be:ident,
|
||||
$au:ident,
|
||||
$cand:ident,
|
||||
$ce:ident,
|
||||
$schema:ident,
|
||||
$target_plugin:ty
|
||||
) => {{
|
||||
let mut audit_scope = AuditScope::new(<($target_plugin)>::id());
|
||||
let r = audit_segment!(audit_scope, || {
|
||||
<($target_plugin)>::pre_create(
|
||||
$be, &mut audit_scope, $cand, $ce, $schema
|
||||
)
|
||||
});
|
||||
$au.append_scope(audit_scope);
|
||||
r
|
||||
}}
|
||||
}
|
||||
|
||||
impl Plugins {
|
||||
pub fn run_pre_create(
|
||||
be: &mut Backend,
|
||||
au: &mut AuditScope,
|
||||
cand: &mut Vec<Entry>,
|
||||
ce: &CreateEvent,
|
||||
schema: &Schema,
|
||||
) -> Result<(), OperationError> {
|
||||
audit_segment!(audit_plugin_pre, || {
|
||||
|
||||
// map chain?
|
||||
let uuid_res = run_pre_create_plugin!(be, au, cand, ce, schema, uuid::UUID);
|
||||
|
||||
|
||||
// TODO, actually return the right thing ...
|
||||
uuid_res
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We should define the order that plugins should run
|
||||
|
||||
|
|
|
@ -9,9 +9,12 @@ use event::CreateEvent;
|
|||
use filter::Filter;
|
||||
use schema::Schema;
|
||||
|
||||
struct UUID {}
|
||||
pub struct UUID {}
|
||||
|
||||
impl Plugin for UUID {
|
||||
fn id() -> &'static str {
|
||||
"UUID"
|
||||
}
|
||||
// Need to be given the backend(for testing ease)
|
||||
// audit
|
||||
// the mut set of entries to create
|
||||
|
@ -30,17 +33,36 @@ impl Plugin for UUID {
|
|||
for entry in cand.iter_mut() {
|
||||
let name_uuid = String::from("uuid");
|
||||
|
||||
audit_log!(au, "UUID check on entry: {:?}", entry);
|
||||
|
||||
// if they don't have uuid, create it.
|
||||
// TODO: get_ava should have a str version for effeciency?
|
||||
let mut c_uuid = match entry.get_ava(&name_uuid) {
|
||||
Some(u) => {
|
||||
// Actually check we have a value, could be empty array ...
|
||||
let v = u.first().unwrap();
|
||||
if u.len() > 1 {
|
||||
audit_log!(au, "Entry defines uuid attr, but multiple values.");
|
||||
return Err(OperationError::Plugin)
|
||||
};
|
||||
|
||||
let v = match u.first() {
|
||||
Some(v) => v,
|
||||
None => {
|
||||
audit_log!(au, "Entry defines uuid attr, but no value.");
|
||||
return Err(OperationError::Plugin)
|
||||
}
|
||||
};
|
||||
|
||||
// This could actually fail, so we probably need to handle
|
||||
// this better ....
|
||||
// TODO: Make this a SCHEMA check, not a manual one.
|
||||
//
|
||||
match Uuid::parse_str(v.as_str()) {
|
||||
Ok(up) => up,
|
||||
Err(_) => return Err(OperationError::Plugin),
|
||||
Err(_) => {
|
||||
audit_log!(au, "Entry contains invalid UUID content, rejecting out of principle.");
|
||||
return Err(OperationError::Plugin)
|
||||
}
|
||||
}
|
||||
}
|
||||
None => Uuid::new_v4(),
|
||||
|
@ -48,7 +70,6 @@ impl Plugin for UUID {
|
|||
|
||||
// Make it a string, so we can filter.
|
||||
let str_uuid = format!("{}", c_uuid);
|
||||
println!("{}", str_uuid);
|
||||
|
||||
let mut au_be = AuditScope::new("be_exist");
|
||||
|
||||
|
@ -58,27 +79,25 @@ impl Plugin for UUID {
|
|||
let r = be.exists(&mut au_be, &filt);
|
||||
|
||||
au.append_scope(au_be);
|
||||
// end the scope?
|
||||
// end the scope for the be operation.
|
||||
|
||||
match r {
|
||||
Ok(b) => {
|
||||
if b == true {
|
||||
audit_log!(au, "UUID already exists, rejecting.");
|
||||
return Err(OperationError::Plugin);
|
||||
}
|
||||
}
|
||||
Err(e) => return Err(OperationError::Plugin),
|
||||
Err(e) => {
|
||||
audit_log!(au, "Backend error occured checking UUID existance.");
|
||||
return Err(OperationError::Plugin)
|
||||
}
|
||||
}
|
||||
|
||||
// check that the uuid is unique in the be (even if one is provided
|
||||
// we especially need to check that)
|
||||
|
||||
// if not unique, generate another, and try again.
|
||||
|
||||
// If it's okay, now put it into the entry.
|
||||
// we may need to inject the base OC required for all objects in our
|
||||
// server to support this?
|
||||
let str_uuid = format!("{}", c_uuid);
|
||||
audit_log!(au, "Set UUID {} to entry", str_uuid);
|
||||
let ava_uuid: Vec<String> = vec![str_uuid];
|
||||
|
||||
entry.set_avas(name_uuid, ava_uuid);
|
||||
}
|
||||
// done!
|
||||
|
@ -142,9 +161,6 @@ mod tests {
|
|||
// Check empty create
|
||||
#[test]
|
||||
fn test_pre_create_empty() {
|
||||
// Need a macro to create all the bits here ...
|
||||
// Macro needs preload entries, the create entries
|
||||
// schema, identity for create event (later)
|
||||
let preload: Vec<Entry> = Vec::new();
|
||||
let mut create: Vec<Entry> = Vec::new();
|
||||
run_pre_create_test!(
|
||||
|
@ -169,9 +185,6 @@ mod tests {
|
|||
// check create where no uuid
|
||||
#[test]
|
||||
fn test_pre_create_no_uuid() {
|
||||
// Need a macro to create all the bits here ...
|
||||
// Macro needs preload entries, the create entries
|
||||
// schema, identity for create event (later)
|
||||
let preload: Vec<Entry> = Vec::new();
|
||||
|
||||
let e: Entry = serde_json::from_str(
|
||||
|
@ -208,16 +221,81 @@ mod tests {
|
|||
}
|
||||
|
||||
// check unparseable uuid
|
||||
#[test]
|
||||
fn test_pre_create_uuid_invalid() {
|
||||
let preload: Vec<Entry> = Vec::new();
|
||||
|
||||
let e: Entry = serde_json::from_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["xxxxxx"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut create = vec![e.clone()];
|
||||
|
||||
run_pre_create_test!(
|
||||
preload,
|
||||
create,
|
||||
false,
|
||||
false,
|
||||
|be: &mut Backend,
|
||||
au: &mut AuditScope,
|
||||
cand: &mut Vec<Entry>,
|
||||
ce: &CreateEvent,
|
||||
schema: &Schema| {
|
||||
let r = UUID::pre_create(be, au, cand, ce, schema);
|
||||
assert!(r.is_err());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// check entry where uuid is empty list
|
||||
#[test]
|
||||
fn test_pre_create_uuid_empty() {
|
||||
let preload: Vec<Entry> = Vec::new();
|
||||
|
||||
let e: Entry = serde_json::from_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": []
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut create = vec![e.clone()];
|
||||
|
||||
run_pre_create_test!(
|
||||
preload,
|
||||
create,
|
||||
false,
|
||||
false,
|
||||
|be: &mut Backend,
|
||||
au: &mut AuditScope,
|
||||
cand: &mut Vec<Entry>,
|
||||
ce: &CreateEvent,
|
||||
schema: &Schema| {
|
||||
let r = UUID::pre_create(be, au, cand, ce, schema);
|
||||
assert!(r.is_err());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// check create where provided uuid is valid. It should be unchanged.
|
||||
|
||||
// check create where uuid already exists.
|
||||
#[test]
|
||||
fn test_pre_create_uuid_exist() {
|
||||
// Need a macro to create all the bits here ...
|
||||
// Macro needs preload entries, the create entries
|
||||
// schema, identity for create event (later)
|
||||
fn test_pre_create_uuid_valid() {
|
||||
let preload: Vec<Entry> = Vec::new();
|
||||
|
||||
let e: Entry = serde_json::from_str(
|
||||
|
@ -234,7 +312,78 @@ mod tests {
|
|||
.unwrap();
|
||||
|
||||
let mut create = vec![e.clone()];
|
||||
let mut preload = vec![e];
|
||||
|
||||
run_pre_create_test!(
|
||||
preload,
|
||||
create,
|
||||
false,
|
||||
false,
|
||||
|be: &mut Backend,
|
||||
au: &mut AuditScope,
|
||||
cand: &mut Vec<Entry>,
|
||||
ce: &CreateEvent,
|
||||
schema: &Schema| {
|
||||
let r = UUID::pre_create(be, au, cand, ce, schema);
|
||||
assert!(r.is_ok());
|
||||
let ue = cand.first().unwrap();
|
||||
assert!(ue.attribute_equality("uuid", "79724141-3603-4060-b6bb-35c72772611d"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_pre_create_uuid_valid_multi() {
|
||||
let preload: Vec<Entry> = Vec::new();
|
||||
|
||||
let e: Entry = serde_json::from_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["79724141-3603-4060-b6bb-35c72772611d", "79724141-3603-4060-b6bb-35c72772611d"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut create = vec![e.clone()];
|
||||
|
||||
run_pre_create_test!(
|
||||
preload,
|
||||
create,
|
||||
false,
|
||||
false,
|
||||
|be: &mut Backend,
|
||||
au: &mut AuditScope,
|
||||
cand: &mut Vec<Entry>,
|
||||
ce: &CreateEvent,
|
||||
schema: &Schema| {
|
||||
let r = UUID::pre_create(be, au, cand, ce, schema);
|
||||
assert!(r.is_err());
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// check create where uuid already exists.
|
||||
#[test]
|
||||
fn test_pre_create_uuid_exist() {
|
||||
let e: Entry = serde_json::from_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["person"],
|
||||
"name": ["testperson"],
|
||||
"description": ["testperson"],
|
||||
"displayname": ["testperson"],
|
||||
"uuid": ["79724141-3603-4060-b6bb-35c72772611d"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut create = vec![e.clone()];
|
||||
let preload = vec![e];
|
||||
|
||||
run_pre_create_test!(
|
||||
preload,
|
||||
|
|
|
@ -668,21 +668,6 @@ impl Schema {
|
|||
.map(|s| (s.clone(), self.attributes.get(s).unwrap()))
|
||||
.collect();
|
||||
|
||||
/*
|
||||
let may: HashMap<String, &SchemaAttribute> = classes
|
||||
.iter()
|
||||
// Join our class systemmmust + must into one iter
|
||||
.flat_map(|(_, cls)| {
|
||||
cls.systemmust
|
||||
.iter()
|
||||
.chain(cls.must.iter())
|
||||
.chain(cls.systemmay.iter())
|
||||
.chain(cls.may.iter())
|
||||
})
|
||||
.map(|s| (s.clone(), self.attributes.get(s).unwrap()))
|
||||
.collect();
|
||||
*/
|
||||
|
||||
// FIXME: Error needs to say what is missing
|
||||
// We need to return *all* missing attributes.
|
||||
|
||||
|
@ -822,7 +807,9 @@ impl Schema {
|
|||
// Normalise *does not* validate.
|
||||
// Normalise just fixes some possible common issues, but it
|
||||
// can't fix *everything* possibly wrong ...
|
||||
pub fn normalise_filter(&mut self) {}
|
||||
pub fn normalise_filter(&mut self) {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -7,7 +7,7 @@ use entry::Entry;
|
|||
use error::OperationError;
|
||||
use event::{CreateEvent, OpResult, SearchEvent, SearchResult};
|
||||
use log::EventLog;
|
||||
use plugins;
|
||||
use plugins::Plugins;
|
||||
use schema::Schema;
|
||||
|
||||
pub fn start(log: actix::Addr<EventLog>, path: &str, threads: usize) -> actix::Addr<QueryServer> {
|
||||
|
@ -96,16 +96,26 @@ impl QueryServer {
|
|||
// based on request size in the frontend?
|
||||
|
||||
// Copy the entries to a writeable form.
|
||||
let mut candidates: Vec<_> = ce.entries.iter().collect();
|
||||
let mut candidates: Vec<Entry> = ce.entries.iter()
|
||||
.map(|er| er.clone())
|
||||
.collect();
|
||||
|
||||
// Start a txn
|
||||
|
||||
// run any pre plugins, giving them the list of mutable candidates.
|
||||
// pre-plugins are defined here in their correct order of calling!
|
||||
// I have no intent to make these dynamic or configurable.
|
||||
|
||||
// Run any pre checks
|
||||
// FIXME: Normalise all entries incoming
|
||||
let mut audit_plugin_pre = AuditScope::new("plugin_pre_create");
|
||||
let plug_pre_res = Plugins::run_pre_create(&mut self.be, &mut audit_plugin_pre, &mut candidates, ce, &self.schema);
|
||||
au.append_scope(audit_plugin_pre);
|
||||
|
||||
let r = ce.entries.iter().fold(Ok(()), |acc, e| {
|
||||
if plug_pre_res.is_err() {
|
||||
audit_log!(au, "Create operation failed (plugin), {:?}", plug_pre_res);
|
||||
return plug_pre_res;
|
||||
}
|
||||
|
||||
let r = candidates.iter().fold(Ok(()), |acc, e| {
|
||||
if acc.is_ok() {
|
||||
self.schema
|
||||
.validate_entry(e)
|
||||
|
@ -115,26 +125,35 @@ impl QueryServer {
|
|||
}
|
||||
});
|
||||
if r.is_err() {
|
||||
audit_log!(au, "Create operation failed (schema), {:?}", r);
|
||||
return r;
|
||||
}
|
||||
|
||||
// FIXME: Normalise all entries now.
|
||||
|
||||
let mut audit_be = AuditScope::new("backend_create");
|
||||
// We may change from ce.entries later to something else?
|
||||
let res = self
|
||||
.be
|
||||
.create(&mut audit_be, &ce.entries)
|
||||
.create(&mut audit_be, &candidates)
|
||||
.map(|_| ())
|
||||
.map_err(|e| match e {
|
||||
BackendError::EmptyRequest => OperationError::EmptyRequest,
|
||||
_ => OperationError::Backend,
|
||||
});
|
||||
au.append_scope(audit_be);
|
||||
|
||||
if res.is_err() {
|
||||
audit_log!(au, "Create operation failed (backend), {:?}", r);
|
||||
return res;
|
||||
}
|
||||
// Run any post plugins
|
||||
|
||||
// Commit/Abort the txn
|
||||
// Commit the txn
|
||||
|
||||
// We are complete, finalise logging and return
|
||||
au.append_scope(audit_be);
|
||||
|
||||
audit_log!(au, "Create operation success");
|
||||
res
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue