use std::collections::BTreeSet;
#[cfg(test)]
use std::sync::Arc;
use kanidm_proto::internal::{
CreateRequest, DeleteRequest, ModifyList as ProtoModifyList, ModifyRequest, OperationError,
SearchRequest, SearchResponse,
};
use kanidm_proto::v1::{Entry as ProtoEntry, WhoamiResponse};
use ldap3_proto::simple::LdapFilter;
use uuid::Uuid;
use crate::entry::{Entry, EntryCommitted, EntryInit, EntryNew, EntryReduced};
use crate::filter::{Filter, FilterInvalid, FilterValid};
use crate::modify::{ModifyInvalid, ModifyList, ModifyValid};
use crate::prelude::*;
use crate::schema::SchemaTransaction;
use crate::value::PartialValue;
#[derive(Debug)]
pub struct SearchResult {
entries: Vec<ProtoEntry>,
}
impl SearchResult {
pub fn new(
qs: &mut QueryServerReadTransaction,
entries: &[Entry<EntryReduced, EntryCommitted>],
) -> Result<Self, OperationError> {
let entries: Result<_, _> = entries
.iter()
.map(|e| {
e.to_pe(qs)
})
.collect();
Ok(SearchResult { entries: entries? })
}
pub fn response(self) -> SearchResponse {
SearchResponse {
entries: self.entries,
}
}
pub fn into_proto_array(self) -> Vec<ProtoEntry> {
self.entries
}
}
#[derive(Debug)]
pub struct SearchEvent {
pub ident: Identity,
pub filter: Filter<FilterValid>,
pub filter_orig: Filter<FilterValid>,
pub attrs: Option<BTreeSet<Attribute>>,
}
impl SearchEvent {
pub fn from_message(
ident: Identity,
req: &SearchRequest,
qs: &mut QueryServerReadTransaction,
) -> Result<Self, OperationError> {
let f = Filter::from_ro(&ident, &req.filter, qs)?;
let filter_orig = f
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
Ok(SearchEvent {
ident,
filter,
filter_orig,
attrs: None,
})
}
pub fn from_internal_message(
ident: Identity,
filter: &Filter<FilterInvalid>,
attrs: Option<&[String]>,
qs: &mut QueryServerReadTransaction,
) -> Result<Self, OperationError> {
let r_attrs: Option<BTreeSet<Attribute>> = attrs.map(|vs| {
vs.iter()
.filter_map(|a| qs.get_schema().normalise_attr_if_exists(a.as_str()))
.collect()
});
if let Some(s) = &r_attrs {
if s.is_empty() {
request_error!("EmptyRequest for attributes");
return Err(OperationError::EmptyRequest);
}
}
let filter_orig = filter.validate(qs.get_schema()).map_err(|e| {
request_error!(?e, "filter schema violation");
OperationError::SchemaViolation(e)
})?;
let filter = filter_orig.clone().into_ignore_hidden();
Ok(SearchEvent {
ident,
filter,
filter_orig,
attrs: r_attrs,
})
}
pub fn from_internal_recycle_message(
ident: Identity,
filter: &Filter<FilterInvalid>,
attrs: Option<&[String]>,
qs: &QueryServerReadTransaction,
) -> Result<Self, OperationError> {
let r_attrs: Option<BTreeSet<Attribute>> = attrs.map(|vs| {
vs.iter()
.filter_map(|a| {
qs.get_schema()
.normalise_attr_if_exists(a.as_str())
.map(|a_str| Attribute::from(a_str.as_str()))
})
.collect()
});
if let Some(s) = &r_attrs {
if s.is_empty() {
return Err(OperationError::EmptyRequest);
}
}
let filter_orig = filter
.validate(qs.get_schema())
.map(|f| f.into_recycled())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone();
Ok(SearchEvent {
ident,
filter,
filter_orig,
attrs: r_attrs,
})
}
pub fn from_whoami_request(
ident: Identity,
qs: &QueryServerReadTransaction,
) -> Result<Self, OperationError> {
let filter_orig = filter_all!(f_self())
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
Ok(SearchEvent {
ident,
filter,
filter_orig,
attrs: None,
})
}
pub fn from_target_uuid_request(
ident: Identity,
target_uuid: Uuid,
qs: &QueryServerReadTransaction,
) -> Result<Self, OperationError> {
let filter_orig = filter_all!(f_eq(Attribute::Uuid, PartialValue::Uuid(target_uuid)))
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
Ok(SearchEvent {
ident,
filter,
filter_orig,
attrs: None,
})
}
#[cfg(test)]
pub fn new_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {
SearchEvent {
ident: Identity::from_impersonate_entry_readonly(e),
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
attrs: None,
}
}
#[cfg(test)]
pub fn new_impersonate_identity(ident: Identity, filter: Filter<FilterInvalid>) -> Self {
SearchEvent {
ident,
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
attrs: None,
}
}
pub fn new_impersonate(
ident: &Identity,
filter: Filter<FilterValid>,
filter_orig: Filter<FilterValid>,
) -> Self {
SearchEvent {
ident: Identity::from_impersonate(ident),
filter,
filter_orig,
attrs: None,
}
}
#[cfg(test)]
pub fn new_rec_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {
let filter_orig = filter.into_valid();
let filter = filter_orig.clone().into_recycled();
SearchEvent {
ident: Identity::from_impersonate_entry_readonly(e),
filter,
filter_orig,
attrs: None,
}
}
#[cfg(test)]
pub fn new_ext_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {
SearchEvent {
ident: Identity::from_impersonate_entry_readonly(e),
filter: filter.clone().into_valid().into_ignore_hidden(),
filter_orig: filter.into_valid(),
attrs: None,
}
}
pub(crate) fn new_ext_impersonate_uuid(
qs: &mut QueryServerReadTransaction,
ident: Identity,
lf: &LdapFilter,
attrs: Option<BTreeSet<Attribute>>,
) -> Result<Self, OperationError> {
let f = Filter::from_ldap_ro(&ident, lf, qs)?;
let filter_orig = f
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
Ok(SearchEvent {
ident,
filter,
filter_orig,
attrs,
})
}
#[cfg(test)]
pub fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
SearchEvent {
ident: Identity::from_internal(),
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
attrs: None,
}
}
pub fn new_internal(filter: Filter<FilterValid>) -> Self {
SearchEvent {
ident: Identity::from_internal(),
filter: filter.clone(),
filter_orig: filter,
attrs: None,
}
}
}
#[derive(Debug)]
pub struct CreateEvent {
pub ident: Identity,
pub entries: Vec<Entry<EntryInit, EntryNew>>,
}
impl CreateEvent {
pub fn from_message(
ident: Identity,
req: &CreateRequest,
qs: &mut QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
let rentries: Result<Vec<_>, _> = req
.entries
.iter()
.map(|e| Entry::from_proto_entry(e, qs))
.collect();
match rentries {
Ok(entries) => Ok(CreateEvent { ident, entries }),
Err(e) => Err(e),
}
}
#[cfg(test)]
pub fn new_impersonate_identity(
ident: Identity,
entries: Vec<Entry<EntryInit, EntryNew>>,
) -> Self {
CreateEvent { ident, entries }
}
pub fn new_internal(entries: Vec<Entry<EntryInit, EntryNew>>) -> Self {
CreateEvent {
ident: Identity::from_internal(),
entries,
}
}
}
#[derive(Debug)]
pub struct ExistsEvent {
pub ident: Identity,
pub filter: Filter<FilterValid>,
pub filter_orig: Filter<FilterValid>,
}
impl ExistsEvent {
pub fn new_internal(filter: Filter<FilterValid>) -> Self {
ExistsEvent {
ident: Identity::from_internal(),
filter: filter.clone(),
filter_orig: filter,
}
}
#[cfg(test)]
pub fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
ExistsEvent {
ident: Identity::from_internal(),
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
}
}
}
#[derive(Debug)]
pub struct DeleteEvent {
pub ident: Identity,
pub filter: Filter<FilterValid>,
pub filter_orig: Filter<FilterValid>,
}
impl DeleteEvent {
pub fn from_message(
ident: Identity,
req: &DeleteRequest,
qs: &mut QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
let f = Filter::from_rw(&ident, &req.filter, qs)?;
let filter_orig = f
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
Ok(DeleteEvent {
ident,
filter,
filter_orig,
})
}
pub fn from_parts(
ident: Identity,
f: &Filter<FilterInvalid>,
qs: &mut QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
let filter_orig = f
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
Ok(DeleteEvent {
ident,
filter,
filter_orig,
})
}
#[cfg(test)]
pub fn new_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {
DeleteEvent {
ident: Identity::from_impersonate_entry_readwrite(e),
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
}
}
#[cfg(test)]
pub fn new_impersonate_identity(ident: Identity, filter: Filter<FilterInvalid>) -> Self {
DeleteEvent {
ident,
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
}
}
#[cfg(test)]
pub fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
DeleteEvent {
ident: Identity::from_internal(),
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
}
}
pub fn new_internal(filter: Filter<FilterValid>) -> Self {
DeleteEvent {
ident: Identity::from_internal(),
filter: filter.clone(),
filter_orig: filter,
}
}
}
#[derive(Debug)]
pub struct ModifyEvent {
pub ident: Identity,
pub filter: Filter<FilterValid>,
pub filter_orig: Filter<FilterValid>,
pub modlist: ModifyList<ModifyValid>,
}
impl ModifyEvent {
pub fn from_message(
ident: Identity,
req: &ModifyRequest,
qs: &mut QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
let f = Filter::from_rw(&ident, &req.filter, qs)?;
let m = ModifyList::from(&req.modlist, qs)?;
let filter_orig = f
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
let modlist = m
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
Ok(ModifyEvent {
ident,
filter,
filter_orig,
modlist,
})
}
pub fn from_parts(
ident: Identity,
target_uuid: Uuid,
proto_ml: &ProtoModifyList,
filter: Filter<FilterInvalid>,
qs: &mut QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
let f_uuid = filter_all!(f_eq(Attribute::Uuid, PartialValue::Uuid(target_uuid)));
let f = Filter::join_parts_and(f_uuid, filter);
let m = ModifyList::from(proto_ml, qs)?;
let filter_orig = f
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
let modlist = m
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
Ok(ModifyEvent {
ident,
filter,
filter_orig,
modlist,
})
}
pub fn from_internal_parts(
ident: Identity,
ml: &ModifyList<ModifyInvalid>,
filter: &Filter<FilterInvalid>,
qs: &QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
let filter_orig = filter
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
let modlist = ml
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
Ok(ModifyEvent {
ident,
filter,
filter_orig,
modlist,
})
}
pub fn from_target_uuid_attr_purge(
ident: Identity,
target_uuid: Uuid,
attr: Attribute,
filter: Filter<FilterInvalid>,
qs: &QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
let ml = ModifyList::new_purge(attr);
let f_uuid = filter_all!(f_eq(Attribute::Uuid, PartialValue::Uuid(target_uuid)));
let f = Filter::join_parts_and(f_uuid, filter);
let filter_orig = f
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
let filter = filter_orig.clone().into_ignore_hidden();
let modlist = ml
.validate(qs.get_schema())
.map_err(OperationError::SchemaViolation)?;
Ok(ModifyEvent {
ident,
filter,
filter_orig,
modlist,
})
}
pub fn new_internal(filter: Filter<FilterValid>, modlist: ModifyList<ModifyValid>) -> Self {
ModifyEvent {
ident: Identity::from_internal(),
filter: filter.clone(),
filter_orig: filter,
modlist,
}
}
#[cfg(test)]
pub fn new_internal_invalid(
filter: Filter<FilterInvalid>,
modlist: ModifyList<ModifyInvalid>,
) -> Self {
ModifyEvent {
ident: Identity::from_internal(),
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
modlist: modlist.into_valid(),
}
}
#[cfg(test)]
pub fn new_impersonate_entry_ser(
e: BuiltinAccount,
filter: Filter<FilterInvalid>,
modlist: ModifyList<ModifyInvalid>,
) -> Self {
let ei: EntryInitNew = e.into();
ModifyEvent {
ident: Identity::from_impersonate_entry_readwrite(Arc::new(ei.into_sealed_committed())),
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
modlist: modlist.into_valid(),
}
}
#[cfg(test)]
pub fn new_impersonate_identity(
ident: Identity,
filter: Filter<FilterInvalid>,
modlist: ModifyList<ModifyInvalid>,
) -> Self {
ModifyEvent {
ident,
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
modlist: modlist.into_valid(),
}
}
#[cfg(test)]
pub fn new_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
modlist: ModifyList<ModifyInvalid>,
) -> Self {
ModifyEvent {
ident: Identity::from_impersonate_entry_readwrite(e),
filter: filter.clone().into_valid(),
filter_orig: filter.into_valid(),
modlist: modlist.into_valid(),
}
}
pub fn new_impersonate(
ident: &Identity,
filter: Filter<FilterValid>,
filter_orig: Filter<FilterValid>,
modlist: ModifyList<ModifyValid>,
) -> Self {
ModifyEvent {
ident: Identity::from_impersonate(ident),
filter,
filter_orig,
modlist,
}
}
}
pub struct WhoamiResult {
youare: ProtoEntry,
}
impl WhoamiResult {
pub fn new(
qs: &mut QueryServerReadTransaction,
e: &Entry<EntryReduced, EntryCommitted>,
) -> Result<Self, OperationError> {
Ok(WhoamiResult {
youare: e.to_pe(qs)?,
})
}
pub fn response(self) -> WhoamiResponse {
WhoamiResponse {
youare: self.youare,
}
}
}
#[derive(Debug)]
pub struct PurgeTombstoneEvent {
pub ident: Identity,
pub eventid: Uuid,
}
impl Default for PurgeTombstoneEvent {
fn default() -> Self {
Self::new()
}
}
impl PurgeTombstoneEvent {
pub fn new() -> Self {
PurgeTombstoneEvent {
ident: Identity::from_internal(),
eventid: Uuid::new_v4(),
}
}
}
#[derive(Debug)]
pub struct PurgeRecycledEvent {
pub ident: Identity,
pub eventid: Uuid,
}
impl Default for PurgeRecycledEvent {
fn default() -> Self {
Self::new()
}
}
impl PurgeRecycledEvent {
pub fn new() -> Self {
PurgeRecycledEvent {
ident: Identity::from_internal(),
eventid: Uuid::new_v4(),
}
}
}
#[derive(Debug)]
pub struct OnlineBackupEvent {
pub ident: Identity,
pub eventid: Uuid,
}
impl Default for OnlineBackupEvent {
fn default() -> Self {
Self::new()
}
}
impl OnlineBackupEvent {
pub fn new() -> Self {
OnlineBackupEvent {
ident: Identity::from_internal(),
eventid: Uuid::new_v4(),
}
}
}
#[derive(Debug)]
pub struct ReviveRecycledEvent {
pub ident: Identity,
pub filter: Filter<FilterValid>,
}
impl ReviveRecycledEvent {
pub fn from_parts(
ident: Identity,
filter: &Filter<FilterInvalid>,
qs: &QueryServerWriteTransaction,
) -> Result<Self, OperationError> {
let filter = filter
.validate(qs.get_schema())
.map(|f| f.into_recycled())
.map_err(OperationError::SchemaViolation)?;
Ok(ReviveRecycledEvent { ident, filter })
}
#[cfg(test)]
pub fn new_impersonate_entry(
e: Arc<Entry<EntrySealed, EntryCommitted>>,
filter: Filter<FilterInvalid>,
) -> Self {
ReviveRecycledEvent {
ident: Identity::from_impersonate_entry_readwrite(e),
filter: filter.into_valid(),
}
}
#[cfg(test)]
pub(crate) fn new_internal(filter: Filter<FilterValid>) -> Self {
ReviveRecycledEvent {
ident: Identity::from_internal(),
filter,
}
}
}