mirror of
https://github.com/kanidm/kanidm.git
synced 2025-05-21 16:33:55 +02:00
20230728 techdebt paydown (#1909)
This commit is contained in:
parent
ea4d755d7b
commit
d731b20a9d
|
@ -451,7 +451,7 @@ pub async fn domain_rename_core(config: &Configuration) {
|
|||
|
||||
let mut qs_write = qs.write(duration_from_epoch_now()).await;
|
||||
let r = qs_write
|
||||
.domain_rename(new_domain_name)
|
||||
.danger_domain_rename(new_domain_name)
|
||||
.and_then(|_| qs_write.commit());
|
||||
|
||||
match r {
|
||||
|
|
|
@ -1062,14 +1062,22 @@ impl<'a> IdlArcSqliteWriteTransaction<'a> {
|
|||
self.db.create_idx(attr, itype)
|
||||
}
|
||||
|
||||
pub unsafe fn purge_idxs(&mut self) -> Result<(), OperationError> {
|
||||
self.db.purge_idxs().map(|()| {
|
||||
/// ⚠️ - This function will destroy all indexes in the database.
|
||||
///
|
||||
/// It should only be called internally by the backend in limited and
|
||||
/// specific situations.
|
||||
pub fn danger_purge_idxs(&mut self) -> Result<(), OperationError> {
|
||||
self.db.danger_purge_idxs().map(|()| {
|
||||
self.idl_cache.clear();
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn purge_id2entry(&mut self) -> Result<(), OperationError> {
|
||||
self.db.purge_id2entry().map(|()| {
|
||||
/// ⚠️ - This function will destroy all entries in the database.
|
||||
///
|
||||
/// It should only be called internally by the backend in limited and
|
||||
/// specific situations.
|
||||
pub fn danger_purge_id2entry(&mut self) -> Result<(), OperationError> {
|
||||
self.db.danger_purge_id2entry().map(|()| {
|
||||
let mut ids = IDLBitRange::new();
|
||||
ids.compress();
|
||||
std::mem::swap(self.allids.deref_mut(), &mut ids);
|
||||
|
|
|
@ -541,14 +541,12 @@ pub trait IdlSqliteTransaction {
|
|||
// This allow is critical as it resolves a life time issue in stmt.
|
||||
#[allow(clippy::let_and_return)]
|
||||
fn verify(&self) -> Vec<Result<(), ConsistencyError>> {
|
||||
let conn = match self.get_conn() {
|
||||
Ok(conn) => conn,
|
||||
Err(_) => return vec![Err(ConsistencyError::SqliteIntegrityFailure)],
|
||||
let Ok(conn) = self.get_conn() else {
|
||||
return vec![Err(ConsistencyError::SqliteIntegrityFailure)]
|
||||
};
|
||||
|
||||
let mut stmt = match conn.prepare("PRAGMA integrity_check;") {
|
||||
Ok(r) => r,
|
||||
Err(_) => return vec![Err(ConsistencyError::SqliteIntegrityFailure)],
|
||||
let Ok(mut stmt) = conn.prepare("PRAGMA integrity_check;") else {
|
||||
return vec![Err(ConsistencyError::SqliteIntegrityFailure)]
|
||||
};
|
||||
|
||||
// Allow this as it actually extends the life of stmt
|
||||
|
@ -1034,7 +1032,11 @@ impl IdlSqliteWriteTransaction {
|
|||
.map_err(sqlite_error)
|
||||
}
|
||||
|
||||
pub unsafe fn purge_idxs(&self) -> Result<(), OperationError> {
|
||||
/// ⚠️ - This function will destroy all indexes in the database.
|
||||
///
|
||||
/// It should only be called internally by the backend in limited and
|
||||
/// specific situations.
|
||||
pub fn danger_purge_idxs(&self) -> Result<(), OperationError> {
|
||||
let idx_table_list = self.list_idxs()?;
|
||||
|
||||
idx_table_list.iter().try_for_each(|idx_table| {
|
||||
|
@ -1124,7 +1126,11 @@ impl IdlSqliteWriteTransaction {
|
|||
Ok(slope)
|
||||
}
|
||||
|
||||
pub unsafe fn purge_id2entry(&self) -> Result<(), OperationError> {
|
||||
/// ⚠️ - This function will destroy all entries in the database.
|
||||
///
|
||||
/// It should only be called internally by the backend in limited and
|
||||
/// specific situations.
|
||||
pub fn danger_purge_id2entry(&self) -> Result<(), OperationError> {
|
||||
self.get_conn()?
|
||||
.execute(&format!("DELETE FROM {}.id2entry", self.get_db_name()), [])
|
||||
.map(|_| ())
|
||||
|
|
|
@ -431,14 +431,11 @@ pub trait BackendTransaction {
|
|||
|
||||
for f in f_andnot.iter() {
|
||||
f_rem_count -= 1;
|
||||
let f_in = match f {
|
||||
FilterResolved::AndNot(f_in, _) => f_in,
|
||||
_ => {
|
||||
filter_error!(
|
||||
"Invalid server state, a cand filter leaked to andnot set!"
|
||||
);
|
||||
return Err(OperationError::InvalidState);
|
||||
}
|
||||
let FilterResolved::AndNot(f_in, _) = f else {
|
||||
filter_error!(
|
||||
"Invalid server state, a cand filter leaked to andnot set!"
|
||||
);
|
||||
return Err(OperationError::InvalidState);
|
||||
};
|
||||
let (inter, fp) = self.filter2idl(f_in, thres)?;
|
||||
// It's an and not, so we need to wrap the plan accordingly.
|
||||
|
@ -754,12 +751,9 @@ pub trait BackendTransaction {
|
|||
// We only check these on live entries.
|
||||
let (n2u_add, n2u_rem) = Entry::idx_name2uuid_diff(None, Some(e));
|
||||
|
||||
let n2u_set = match (n2u_add, n2u_rem) {
|
||||
(Some(set), None) => set,
|
||||
(_, _) => {
|
||||
admin_error!("Invalid idx_name2uuid_diff state");
|
||||
return Err(ConsistencyError::BackendIndexSync);
|
||||
}
|
||||
let (Some(n2u_set), None) = (n2u_add, n2u_rem) else {
|
||||
admin_error!("Invalid idx_name2uuid_diff state");
|
||||
return Err(ConsistencyError::BackendIndexSync);
|
||||
};
|
||||
|
||||
// If the set.len > 1, check each item.
|
||||
|
@ -1588,7 +1582,7 @@ impl<'a> BackendWriteTransaction<'a> {
|
|||
|
||||
pub fn reindex(&mut self) -> Result<(), OperationError> {
|
||||
// Purge the idxs
|
||||
unsafe { self.idlayer.purge_idxs()? };
|
||||
self.idlayer.danger_purge_idxs()?;
|
||||
|
||||
// Using the index metadata on the txn, create all our idx tables
|
||||
self.create_idxs()?;
|
||||
|
@ -1632,17 +1626,23 @@ impl<'a> BackendWriteTransaction<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn purge_idxs(&mut self) -> Result<(), OperationError> {
|
||||
unsafe { self.get_idlayer().purge_idxs() }
|
||||
/// ⚠️ - This function will destroy all indexes in the database.
|
||||
///
|
||||
/// It should only be called internally by the backend in limited and
|
||||
/// specific situations.
|
||||
fn danger_purge_idxs(&mut self) -> Result<(), OperationError> {
|
||||
self.get_idlayer().danger_purge_idxs()
|
||||
}
|
||||
|
||||
/// ⚠️ - This function will destroy all entries and indexes in the database.
|
||||
///
|
||||
/// It should only be called internally by the backend in limited and
|
||||
/// specific situations.
|
||||
pub(crate) fn danger_delete_all_db_content(&mut self) -> Result<(), OperationError> {
|
||||
self.get_ruv().clear();
|
||||
unsafe {
|
||||
self.get_idlayer()
|
||||
.purge_id2entry()
|
||||
.and_then(|_| self.purge_idxs())
|
||||
}
|
||||
self.get_idlayer()
|
||||
.danger_purge_id2entry()
|
||||
.and_then(|_| self.danger_purge_idxs())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -1678,7 +1678,7 @@ impl<'a> BackendWriteTransaction<'a> {
|
|||
OperationError::FsError
|
||||
})?;
|
||||
|
||||
unsafe { idlayer.purge_id2entry() }.map_err(|e| {
|
||||
idlayer.danger_purge_id2entry().map_err(|e| {
|
||||
admin_error!("purge_id2entry failed {:?}", e);
|
||||
e
|
||||
})?;
|
||||
|
@ -1997,10 +1997,10 @@ mod tests {
|
|||
use crate::value::{IndexType, PartialValue, Value};
|
||||
|
||||
lazy_static! {
|
||||
static ref CID_ZERO: Cid = unsafe { Cid::new_zero() };
|
||||
static ref CID_ONE: Cid = unsafe { Cid::new_count(1) };
|
||||
static ref CID_TWO: Cid = unsafe { Cid::new_count(2) };
|
||||
static ref CID_THREE: Cid = unsafe { Cid::new_count(3) };
|
||||
static ref CID_ZERO: Cid = Cid::new_zero();
|
||||
static ref CID_ONE: Cid = Cid::new_count(1);
|
||||
static ref CID_TWO: Cid = Cid::new_count(2);
|
||||
static ref CID_THREE: Cid = Cid::new_count(3);
|
||||
}
|
||||
|
||||
macro_rules! run_test {
|
||||
|
@ -2053,12 +2053,11 @@ mod tests {
|
|||
|
||||
macro_rules! entry_exists {
|
||||
($be:expr, $ent:expr) => {{
|
||||
let ei = unsafe { $ent.clone().into_sealed_committed() };
|
||||
let filt = unsafe {
|
||||
ei.filter_from_attrs(&vec![AttrString::from("uuid")])
|
||||
.expect("failed to generate filter")
|
||||
.into_valid_resolved()
|
||||
};
|
||||
let ei = $ent.clone().into_sealed_committed();
|
||||
let filt = ei
|
||||
.filter_from_attrs(&vec![AttrString::from("uuid")])
|
||||
.expect("failed to generate filter")
|
||||
.into_valid_resolved();
|
||||
let lims = Limits::unlimited();
|
||||
let entries = $be.search(&lims, &filt).expect("failed to search");
|
||||
entries.first().is_some()
|
||||
|
@ -2067,12 +2066,11 @@ mod tests {
|
|||
|
||||
macro_rules! entry_attr_pres {
|
||||
($be:expr, $ent:expr, $attr:expr) => {{
|
||||
let ei = unsafe { $ent.clone().into_sealed_committed() };
|
||||
let filt = unsafe {
|
||||
ei.filter_from_attrs(&vec![AttrString::from("userid")])
|
||||
.expect("failed to generate filter")
|
||||
.into_valid_resolved()
|
||||
};
|
||||
let ei = $ent.clone().into_sealed_committed();
|
||||
let filt = ei
|
||||
.filter_from_attrs(&vec![AttrString::from("userid")])
|
||||
.expect("failed to generate filter")
|
||||
.into_valid_resolved();
|
||||
let lims = Limits::unlimited();
|
||||
let entries = $be.search(&lims, &filt).expect("failed to search");
|
||||
match entries.first() {
|
||||
|
@ -2104,7 +2102,7 @@ mod tests {
|
|||
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e.add_ava("userid", Value::from("william"));
|
||||
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
let e = unsafe { e.into_sealed_new() };
|
||||
let e = e.into_sealed_new();
|
||||
|
||||
let single_result = be.create(&CID_ZERO, vec![e.clone()]);
|
||||
|
||||
|
@ -2123,14 +2121,13 @@ mod tests {
|
|||
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e.add_ava("userid", Value::from("claire"));
|
||||
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
let e = unsafe { e.into_sealed_new() };
|
||||
let e = e.into_sealed_new();
|
||||
|
||||
let single_result = be.create(&CID_ZERO, vec![e]);
|
||||
assert!(single_result.is_ok());
|
||||
// Test a simple EQ search
|
||||
|
||||
let filt =
|
||||
unsafe { filter_resolved!(f_eq("userid", PartialValue::new_utf8s("claire"))) };
|
||||
let filt = filter_resolved!(f_eq("userid", PartialValue::new_utf8s("claire")));
|
||||
|
||||
let lims = Limits::unlimited();
|
||||
|
||||
|
@ -2159,8 +2156,8 @@ mod tests {
|
|||
e2.add_ava("userid", Value::from("alice"));
|
||||
e2.add_ava("uuid", Value::from("4b6228ab-1dbe-42a4-a9f5-f6368222438e"));
|
||||
|
||||
let ve1 = unsafe { e1.clone().into_sealed_new() };
|
||||
let ve2 = unsafe { e2.clone().into_sealed_new() };
|
||||
let ve1 = e1.clone().into_sealed_new();
|
||||
let ve2 = e2.clone().into_sealed_new();
|
||||
|
||||
assert!(be.create(&CID_ZERO, vec![ve1, ve2]).is_ok());
|
||||
assert!(entry_exists!(be, e1));
|
||||
|
@ -2168,20 +2165,20 @@ mod tests {
|
|||
|
||||
// You need to now retrieve the entries back out to get the entry id's
|
||||
let mut results = be
|
||||
.search(&lims, unsafe { &filter_resolved!(f_pres("userid")) })
|
||||
.search(&lims, &filter_resolved!(f_pres("userid")))
|
||||
.expect("Failed to search");
|
||||
|
||||
// Get these out to usable entries.
|
||||
let r1 = results.remove(0);
|
||||
let r2 = results.remove(0);
|
||||
|
||||
let mut r1 = unsafe { r1.as_ref().clone().into_invalid() };
|
||||
let mut r2 = unsafe { r2.as_ref().clone().into_invalid() };
|
||||
let mut r1 = r1.as_ref().clone().into_invalid();
|
||||
let mut r2 = r2.as_ref().clone().into_invalid();
|
||||
|
||||
// Modify no id (err)
|
||||
// This is now impossible due to the state machine design.
|
||||
// However, with some unsafe ....
|
||||
let ue1 = unsafe { e1.clone().into_sealed_committed() };
|
||||
let ue1 = e1.clone().into_sealed_committed();
|
||||
assert!(be
|
||||
.modify(&CID_ZERO, &[Arc::new(ue1.clone())], &[ue1])
|
||||
.is_err());
|
||||
|
@ -2189,15 +2186,15 @@ mod tests {
|
|||
assert!(be.modify(&CID_ZERO, &[], &[]).is_err());
|
||||
|
||||
// Make some changes to r1, r2.
|
||||
let pre1 = unsafe { Arc::new(r1.clone().into_sealed_committed()) };
|
||||
let pre2 = unsafe { Arc::new(r2.clone().into_sealed_committed()) };
|
||||
let pre1 = Arc::new(r1.clone().into_sealed_committed());
|
||||
let pre2 = Arc::new(r2.clone().into_sealed_committed());
|
||||
r1.add_ava("desc", Value::from("modified"));
|
||||
r2.add_ava("desc", Value::from("modified"));
|
||||
|
||||
// Now ... cheat.
|
||||
|
||||
let vr1 = unsafe { r1.into_sealed_committed() };
|
||||
let vr2 = unsafe { r2.into_sealed_committed() };
|
||||
let vr1 = r1.into_sealed_committed();
|
||||
let vr2 = r2.into_sealed_committed();
|
||||
|
||||
// Modify single
|
||||
assert!(be.modify(&CID_ZERO, &[pre1], &[vr1.clone()]).is_ok());
|
||||
|
@ -2238,9 +2235,9 @@ mod tests {
|
|||
e3.add_ava("userid", Value::from("lucy"));
|
||||
e3.add_ava("uuid", Value::from("7b23c99d-c06b-4a9a-a958-3afa56383e1d"));
|
||||
|
||||
let ve1 = unsafe { e1.clone().into_sealed_new() };
|
||||
let ve2 = unsafe { e2.clone().into_sealed_new() };
|
||||
let ve3 = unsafe { e3.clone().into_sealed_new() };
|
||||
let ve1 = e1.clone().into_sealed_new();
|
||||
let ve2 = e2.clone().into_sealed_new();
|
||||
let ve3 = e3.clone().into_sealed_new();
|
||||
|
||||
assert!(be.create(&CID_ZERO, vec![ve1, ve2, ve3]).is_ok());
|
||||
assert!(entry_exists!(be, e1));
|
||||
|
@ -2249,7 +2246,7 @@ mod tests {
|
|||
|
||||
// You need to now retrieve the entries back out to get the entry id's
|
||||
let mut results = be
|
||||
.search(&lims, unsafe { &filter_resolved!(f_pres("userid")) })
|
||||
.search(&lims, &filter_resolved!(f_pres("userid")))
|
||||
.expect("Failed to search");
|
||||
|
||||
// Get these out to usable entries.
|
||||
|
@ -2262,12 +2259,12 @@ mod tests {
|
|||
|
||||
// Put them into the tombstone state, and write that down.
|
||||
// This sets up the RUV with the changes.
|
||||
let r1_ts = unsafe { r1.to_tombstone(CID_ONE.clone()).into_sealed_committed() };
|
||||
let r1_ts = r1.to_tombstone(CID_ONE.clone()).into_sealed_committed();
|
||||
|
||||
assert!(be.modify(&CID_ONE, &[r1], &[r1_ts.clone()]).is_ok());
|
||||
|
||||
let r2_ts = unsafe { r2.to_tombstone(CID_TWO.clone()).into_sealed_committed() };
|
||||
let r3_ts = unsafe { r3.to_tombstone(CID_TWO.clone()).into_sealed_committed() };
|
||||
let r2_ts = r2.to_tombstone(CID_TWO.clone()).into_sealed_committed();
|
||||
let r3_ts = r3.to_tombstone(CID_TWO.clone()).into_sealed_committed();
|
||||
|
||||
assert!(be
|
||||
.modify(&CID_TWO, &[r2, r3], &[r2_ts.clone(), r3_ts.clone()])
|
||||
|
@ -2334,9 +2331,9 @@ mod tests {
|
|||
e3.add_ava("userid", Value::from("lucy"));
|
||||
e3.add_ava("uuid", Value::from("7b23c99d-c06b-4a9a-a958-3afa56383e1d"));
|
||||
|
||||
let ve1 = unsafe { e1.clone().into_sealed_new() };
|
||||
let ve2 = unsafe { e2.clone().into_sealed_new() };
|
||||
let ve3 = unsafe { e3.clone().into_sealed_new() };
|
||||
let ve1 = e1.clone().into_sealed_new();
|
||||
let ve2 = e2.clone().into_sealed_new();
|
||||
let ve3 = e3.clone().into_sealed_new();
|
||||
|
||||
assert!(be.create(&CID_ZERO, vec![ve1, ve2, ve3]).is_ok());
|
||||
assert!(entry_exists!(be, e1));
|
||||
|
@ -2389,9 +2386,9 @@ mod tests {
|
|||
e3.add_ava("userid", Value::from("lucy"));
|
||||
e3.add_ava("uuid", Value::from("7b23c99d-c06b-4a9a-a958-3afa56383e1d"));
|
||||
|
||||
let ve1 = unsafe { e1.clone().into_sealed_new() };
|
||||
let ve2 = unsafe { e2.clone().into_sealed_new() };
|
||||
let ve3 = unsafe { e3.clone().into_sealed_new() };
|
||||
let ve1 = e1.clone().into_sealed_new();
|
||||
let ve2 = e2.clone().into_sealed_new();
|
||||
let ve3 = e3.clone().into_sealed_new();
|
||||
|
||||
assert!(be.create(&CID_ZERO, vec![ve1, ve2, ve3]).is_ok());
|
||||
assert!(entry_exists!(be, e1));
|
||||
|
@ -2475,17 +2472,17 @@ mod tests {
|
|||
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e1.add_ava("name", Value::new_iname("william"));
|
||||
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
let e1 = unsafe { e1.into_sealed_new() };
|
||||
let e1 = e1.into_sealed_new();
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("name", Value::new_iname("claire"));
|
||||
e2.add_ava("uuid", Value::from("bd651620-00dd-426b-aaa0-4494f7b7906f"));
|
||||
let e2 = unsafe { e2.into_sealed_new() };
|
||||
let e2 = e2.into_sealed_new();
|
||||
|
||||
be.create(&CID_ZERO, vec![e1, e2]).unwrap();
|
||||
|
||||
// purge indexes
|
||||
be.purge_idxs().unwrap();
|
||||
be.danger_purge_idxs().unwrap();
|
||||
// Check they are gone
|
||||
let missing = be.missing_idxs().unwrap();
|
||||
assert!(missing.len() == 7);
|
||||
|
@ -2572,7 +2569,7 @@ mod tests {
|
|||
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e1.add_ava("name", Value::from("william"));
|
||||
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
let e1 = unsafe { e1.into_sealed_new() };
|
||||
let e1 = e1.into_sealed_new();
|
||||
|
||||
let rset = be.create(&CID_ZERO, vec![e1]).unwrap();
|
||||
let mut rset: Vec<_> = rset.into_iter().map(Arc::new).collect();
|
||||
|
@ -2598,7 +2595,7 @@ mod tests {
|
|||
assert!(be.uuid2rdn(william_uuid) == Ok(Some("name=william".to_string())));
|
||||
|
||||
// == Now we reap_tombstones, and assert we removed the items.
|
||||
let e1_ts = unsafe { e1.to_tombstone(CID_ONE.clone()).into_sealed_committed() };
|
||||
let e1_ts = e1.to_tombstone(CID_ONE.clone()).into_sealed_committed();
|
||||
assert!(be.modify(&CID_ONE, &[e1], &[e1_ts]).is_ok());
|
||||
be.reap_tombstones(&CID_TWO).unwrap();
|
||||
|
||||
|
@ -2633,17 +2630,17 @@ mod tests {
|
|||
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e1.add_ava("name", Value::new_iname("william"));
|
||||
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
let e1 = unsafe { e1.into_sealed_new() };
|
||||
let e1 = e1.into_sealed_new();
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("name", Value::new_iname("claire"));
|
||||
e2.add_ava("uuid", Value::from("bd651620-00dd-426b-aaa0-4494f7b7906f"));
|
||||
let e2 = unsafe { e2.into_sealed_new() };
|
||||
let e2 = e2.into_sealed_new();
|
||||
|
||||
let mut e3: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e3.add_ava("userid", Value::new_iname("lucy"));
|
||||
e3.add_ava("uuid", Value::from("7b23c99d-c06b-4a9a-a958-3afa56383e1d"));
|
||||
let e3 = unsafe { e3.into_sealed_new() };
|
||||
let e3 = e3.into_sealed_new();
|
||||
|
||||
let mut rset = be.create(&CID_ZERO, vec![e1, e2, e3]).unwrap();
|
||||
rset.remove(1);
|
||||
|
@ -2652,8 +2649,8 @@ mod tests {
|
|||
let e3 = rset.pop().unwrap();
|
||||
|
||||
// Now remove e1, e3.
|
||||
let e1_ts = unsafe { e1.to_tombstone(CID_ONE.clone()).into_sealed_committed() };
|
||||
let e3_ts = unsafe { e3.to_tombstone(CID_ONE.clone()).into_sealed_committed() };
|
||||
let e1_ts = e1.to_tombstone(CID_ONE.clone()).into_sealed_committed();
|
||||
let e3_ts = e3.to_tombstone(CID_ONE.clone()).into_sealed_committed();
|
||||
assert!(be.modify(&CID_ONE, &[e1, e3], &[e1_ts, e3_ts]).is_ok());
|
||||
be.reap_tombstones(&CID_TWO).unwrap();
|
||||
|
||||
|
@ -2702,12 +2699,12 @@ mod tests {
|
|||
e1.add_ava("name", Value::new_iname("william"));
|
||||
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
e1.add_ava("ta", Value::from("test"));
|
||||
let e1 = unsafe { e1.into_sealed_new() };
|
||||
let e1 = e1.into_sealed_new();
|
||||
|
||||
let rset = be.create(&CID_ZERO, vec![e1]).unwrap();
|
||||
let rset: Vec<_> = rset.into_iter().map(Arc::new).collect();
|
||||
// Now, alter the new entry.
|
||||
let mut ce1 = unsafe { rset[0].as_ref().clone().into_invalid() };
|
||||
let mut ce1 = rset[0].as_ref().clone().into_invalid();
|
||||
// add something.
|
||||
ce1.add_ava("tb", Value::from("test"));
|
||||
// remove something.
|
||||
|
@ -2716,7 +2713,7 @@ mod tests {
|
|||
ce1.purge_ava("name");
|
||||
ce1.add_ava("name", Value::new_iname("claire"));
|
||||
|
||||
let ce1 = unsafe { ce1.into_sealed_committed() };
|
||||
let ce1 = ce1.into_sealed_committed();
|
||||
|
||||
be.modify(&CID_ZERO, &rset, &[ce1]).unwrap();
|
||||
|
||||
|
@ -2747,17 +2744,17 @@ mod tests {
|
|||
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e1.add_ava("name", Value::new_iname("william"));
|
||||
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
let e1 = unsafe { e1.into_sealed_new() };
|
||||
let e1 = e1.into_sealed_new();
|
||||
|
||||
let rset = be.create(&CID_ZERO, vec![e1]).unwrap();
|
||||
let rset: Vec<_> = rset.into_iter().map(Arc::new).collect();
|
||||
// Now, alter the new entry.
|
||||
let mut ce1 = unsafe { rset[0].as_ref().clone().into_invalid() };
|
||||
let mut ce1 = rset[0].as_ref().clone().into_invalid();
|
||||
ce1.purge_ava("name");
|
||||
ce1.purge_ava("uuid");
|
||||
ce1.add_ava("name", Value::new_iname("claire"));
|
||||
ce1.add_ava("uuid", Value::from("04091a7a-6ce4-42d2-abf5-c2ce244ac9e8"));
|
||||
let ce1 = unsafe { ce1.into_sealed_committed() };
|
||||
let ce1 = ce1.into_sealed_committed();
|
||||
|
||||
be.modify(&CID_ZERO, &rset, &[ce1]).unwrap();
|
||||
|
||||
|
@ -2805,17 +2802,16 @@ mod tests {
|
|||
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
e1.add_ava("no-index", Value::from("william"));
|
||||
e1.add_ava("other-no-index", Value::from("william"));
|
||||
let e1 = unsafe { e1.into_sealed_new() };
|
||||
let e1 = e1.into_sealed_new();
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("name", Value::new_iname("claire"));
|
||||
e2.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d2"));
|
||||
let e2 = unsafe { e2.into_sealed_new() };
|
||||
let e2 = e2.into_sealed_new();
|
||||
|
||||
let _rset = be.create(&CID_ZERO, vec![e1, e2]).unwrap();
|
||||
// Test fully unindexed
|
||||
let f_un =
|
||||
unsafe { filter_resolved!(f_eq("no-index", PartialValue::new_utf8s("william"))) };
|
||||
let f_un = filter_resolved!(f_eq("no-index", PartialValue::new_utf8s("william")));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_un.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2826,7 +2822,7 @@ mod tests {
|
|||
}
|
||||
|
||||
// Test that a fully indexed search works
|
||||
let feq = unsafe { filter_resolved!(f_eq("name", PartialValue::new_utf8s("william"))) };
|
||||
let feq = filter_resolved!(f_eq("name", PartialValue::new_utf8s("william")));
|
||||
|
||||
let (r, _plan) = be.filter2idl(feq.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2840,15 +2836,13 @@ mod tests {
|
|||
|
||||
// Test and/or
|
||||
// full index and
|
||||
let f_in_and = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_eq("name", PartialValue::new_utf8s("william")),
|
||||
f_eq(
|
||||
"uuid",
|
||||
PartialValue::new_utf8s("db237e8a-0079-4b8c-8a56-593b22aa44d1")
|
||||
)
|
||||
]))
|
||||
};
|
||||
let f_in_and = filter_resolved!(f_and!([
|
||||
f_eq("name", PartialValue::new_utf8s("william")),
|
||||
f_eq(
|
||||
"uuid",
|
||||
PartialValue::new_utf8s("db237e8a-0079-4b8c-8a56-593b22aa44d1")
|
||||
)
|
||||
]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_in_and.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2861,19 +2855,15 @@ mod tests {
|
|||
}
|
||||
|
||||
// partial index and
|
||||
let f_p1 = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_eq("name", PartialValue::new_utf8s("william")),
|
||||
f_eq("no-index", PartialValue::new_utf8s("william"))
|
||||
]))
|
||||
};
|
||||
let f_p1 = filter_resolved!(f_and!([
|
||||
f_eq("name", PartialValue::new_utf8s("william")),
|
||||
f_eq("no-index", PartialValue::new_utf8s("william"))
|
||||
]));
|
||||
|
||||
let f_p2 = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_eq("name", PartialValue::new_utf8s("william")),
|
||||
f_eq("no-index", PartialValue::new_utf8s("william"))
|
||||
]))
|
||||
};
|
||||
let f_p2 = filter_resolved!(f_and!([
|
||||
f_eq("name", PartialValue::new_utf8s("william")),
|
||||
f_eq("no-index", PartialValue::new_utf8s("william"))
|
||||
]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_p1.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2896,12 +2886,10 @@ mod tests {
|
|||
}
|
||||
|
||||
// no index and
|
||||
let f_no_and = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_eq("no-index", PartialValue::new_utf8s("william")),
|
||||
f_eq("other-no-index", PartialValue::new_utf8s("william"))
|
||||
]))
|
||||
};
|
||||
let f_no_and = filter_resolved!(f_and!([
|
||||
f_eq("no-index", PartialValue::new_utf8s("william")),
|
||||
f_eq("other-no-index", PartialValue::new_utf8s("william"))
|
||||
]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_no_and.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2912,9 +2900,8 @@ mod tests {
|
|||
}
|
||||
|
||||
// full index or
|
||||
let f_in_or = unsafe {
|
||||
filter_resolved!(f_or!([f_eq("name", PartialValue::new_utf8s("william"))]))
|
||||
};
|
||||
let f_in_or =
|
||||
filter_resolved!(f_or!([f_eq("name", PartialValue::new_utf8s("william"))]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_in_or.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2926,12 +2913,10 @@ mod tests {
|
|||
}
|
||||
}
|
||||
// partial (aka allids) or
|
||||
let f_un_or = unsafe {
|
||||
filter_resolved!(f_or!([f_eq(
|
||||
"no-index",
|
||||
PartialValue::new_utf8s("william")
|
||||
)]))
|
||||
};
|
||||
let f_un_or = filter_resolved!(f_or!([f_eq(
|
||||
"no-index",
|
||||
PartialValue::new_utf8s("william")
|
||||
)]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_un_or.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2942,9 +2927,8 @@ mod tests {
|
|||
}
|
||||
|
||||
// Test root andnot
|
||||
let f_r_andnot = unsafe {
|
||||
filter_resolved!(f_andnot(f_eq("name", PartialValue::new_utf8s("william"))))
|
||||
};
|
||||
let f_r_andnot =
|
||||
filter_resolved!(f_andnot(f_eq("name", PartialValue::new_utf8s("william"))));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_r_andnot.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2957,12 +2941,10 @@ mod tests {
|
|||
}
|
||||
|
||||
// test andnot as only in and
|
||||
let f_and_andnot = unsafe {
|
||||
filter_resolved!(f_and!([f_andnot(f_eq(
|
||||
"name",
|
||||
PartialValue::new_utf8s("william")
|
||||
))]))
|
||||
};
|
||||
let f_and_andnot = filter_resolved!(f_and!([f_andnot(f_eq(
|
||||
"name",
|
||||
PartialValue::new_utf8s("william")
|
||||
))]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2974,12 +2956,10 @@ mod tests {
|
|||
}
|
||||
}
|
||||
// test andnot as only in or
|
||||
let f_or_andnot = unsafe {
|
||||
filter_resolved!(f_or!([f_andnot(f_eq(
|
||||
"name",
|
||||
PartialValue::new_utf8s("william")
|
||||
))]))
|
||||
};
|
||||
let f_or_andnot = filter_resolved!(f_or!([f_andnot(f_eq(
|
||||
"name",
|
||||
PartialValue::new_utf8s("william")
|
||||
))]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_or_andnot.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -2992,12 +2972,10 @@ mod tests {
|
|||
}
|
||||
|
||||
// test andnot in and (first) with name
|
||||
let f_and_andnot = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_andnot(f_eq("name", PartialValue::new_utf8s("claire"))),
|
||||
f_pres("name")
|
||||
]))
|
||||
};
|
||||
let f_and_andnot = filter_resolved!(f_and!([
|
||||
f_andnot(f_eq("name", PartialValue::new_utf8s("claire"))),
|
||||
f_pres("name")
|
||||
]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -3010,12 +2988,10 @@ mod tests {
|
|||
}
|
||||
}
|
||||
// test andnot in and (last) with name
|
||||
let f_and_andnot = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_pres("name"),
|
||||
f_andnot(f_eq("name", PartialValue::new_utf8s("claire")))
|
||||
]))
|
||||
};
|
||||
let f_and_andnot = filter_resolved!(f_and!([
|
||||
f_pres("name"),
|
||||
f_andnot(f_eq("name", PartialValue::new_utf8s("claire")))
|
||||
]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -3027,12 +3003,10 @@ mod tests {
|
|||
}
|
||||
}
|
||||
// test andnot in and (first) with no-index
|
||||
let f_and_andnot = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_andnot(f_eq("name", PartialValue::new_utf8s("claire"))),
|
||||
f_pres("no-index")
|
||||
]))
|
||||
};
|
||||
let f_and_andnot = filter_resolved!(f_and!([
|
||||
f_andnot(f_eq("name", PartialValue::new_utf8s("claire"))),
|
||||
f_pres("no-index")
|
||||
]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -3042,12 +3016,10 @@ mod tests {
|
|||
}
|
||||
}
|
||||
// test andnot in and (last) with no-index
|
||||
let f_and_andnot = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_pres("no-index"),
|
||||
f_andnot(f_eq("name", PartialValue::new_utf8s("claire")))
|
||||
]))
|
||||
};
|
||||
let f_and_andnot = filter_resolved!(f_and!([
|
||||
f_pres("no-index"),
|
||||
f_andnot(f_eq("name", PartialValue::new_utf8s("claire")))
|
||||
]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_and_andnot.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -3058,7 +3030,7 @@ mod tests {
|
|||
}
|
||||
|
||||
// empty or
|
||||
let f_e_or = unsafe { filter_resolved!(f_or!([])) };
|
||||
let f_e_or = filter_resolved!(f_or!([]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_e_or.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -3070,7 +3042,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let f_e_and = unsafe { filter_resolved!(f_and!([])) };
|
||||
let f_e_and = filter_resolved!(f_and!([]));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_e_and.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -3089,10 +3061,9 @@ mod tests {
|
|||
run_test!(|be: &mut BackendWriteTransaction| {
|
||||
// Test where the index is in schema but not created (purge idxs)
|
||||
// should fall back to an empty set because we can't satisfy the term
|
||||
be.purge_idxs().unwrap();
|
||||
be.danger_purge_idxs().unwrap();
|
||||
debug!("{:?}", be.missing_idxs().unwrap());
|
||||
let f_eq =
|
||||
unsafe { filter_resolved!(f_eq("name", PartialValue::new_utf8s("william"))) };
|
||||
let f_eq = filter_resolved!(f_eq("name", PartialValue::new_utf8s("william")));
|
||||
|
||||
let (r, _plan) = be.filter2idl(f_eq.to_inner(), 0).unwrap();
|
||||
match r {
|
||||
|
@ -3113,21 +3084,21 @@ mod tests {
|
|||
e1.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
e1.add_ava("ta", Value::from("dupe"));
|
||||
e1.add_ava("tb", Value::from("1"));
|
||||
let e1 = unsafe { e1.into_sealed_new() };
|
||||
let e1 = e1.into_sealed_new();
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("name", Value::new_iname("claire"));
|
||||
e2.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d2"));
|
||||
e2.add_ava("ta", Value::from("dupe"));
|
||||
e2.add_ava("tb", Value::from("1"));
|
||||
let e2 = unsafe { e2.into_sealed_new() };
|
||||
let e2 = e2.into_sealed_new();
|
||||
|
||||
let mut e3: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e3.add_ava("name", Value::new_iname("benny"));
|
||||
e3.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d3"));
|
||||
e3.add_ava("ta", Value::from("dupe"));
|
||||
e3.add_ava("tb", Value::from("2"));
|
||||
let e3 = unsafe { e3.into_sealed_new() };
|
||||
let e3 = e3.into_sealed_new();
|
||||
|
||||
let _rset = be.create(&CID_ZERO, vec![e1, e2, e3]).unwrap();
|
||||
|
||||
|
@ -3212,15 +3183,14 @@ mod tests {
|
|||
e.add_ava("userid", Value::from("william"));
|
||||
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
e.add_ava("nonexist", Value::from("x"));
|
||||
let e = unsafe { e.into_sealed_new() };
|
||||
let e = e.into_sealed_new();
|
||||
let single_result = be.create(&CID_ZERO, vec![e.clone()]);
|
||||
|
||||
assert!(single_result.is_ok());
|
||||
let filt = unsafe {
|
||||
e.filter_from_attrs(&[AttrString::from("nonexist")])
|
||||
.expect("failed to generate filter")
|
||||
.into_valid_resolved()
|
||||
};
|
||||
let filt = e
|
||||
.filter_from_attrs(&[AttrString::from("nonexist")])
|
||||
.expect("failed to generate filter")
|
||||
.into_valid_resolved();
|
||||
// check allow on allids
|
||||
let res = be.search(&lim_allow_allids, &filt);
|
||||
assert!(res.is_ok());
|
||||
|
@ -3248,15 +3218,14 @@ mod tests {
|
|||
e.add_ava("userid", Value::from("william"));
|
||||
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
e.add_ava("nonexist", Value::from("x"));
|
||||
let e = unsafe { e.into_sealed_new() };
|
||||
let e = e.into_sealed_new();
|
||||
let single_result = be.create(&CID_ZERO, vec![e.clone()]);
|
||||
assert!(single_result.is_ok());
|
||||
|
||||
let filt = unsafe {
|
||||
e.filter_from_attrs(&[AttrString::from("nonexist")])
|
||||
.expect("failed to generate filter")
|
||||
.into_valid_resolved()
|
||||
};
|
||||
let filt = e
|
||||
.filter_from_attrs(&[AttrString::from("nonexist")])
|
||||
.expect("failed to generate filter")
|
||||
.into_valid_resolved();
|
||||
|
||||
// --> This is the all ids path (unindexed)
|
||||
// check allow on entry max
|
||||
|
@ -3306,7 +3275,7 @@ mod tests {
|
|||
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
e.add_ava("nonexist", Value::from("x"));
|
||||
e.add_ava("nonexist", Value::from("y"));
|
||||
let e = unsafe { e.into_sealed_new() };
|
||||
let e = e.into_sealed_new();
|
||||
let single_result = be.create(&CID_ZERO, vec![e]);
|
||||
assert!(single_result.is_ok());
|
||||
|
||||
|
@ -3323,18 +3292,16 @@ mod tests {
|
|||
//
|
||||
// This creates a partial, and because it's the first iteration in the loop, this
|
||||
// doesn't encounter partial threshold testing.
|
||||
let filt = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_or!([
|
||||
f_eq("nonexist", PartialValue::new_utf8s("x")),
|
||||
f_eq("nonexist", PartialValue::new_utf8s("y"))
|
||||
]),
|
||||
f_or!([
|
||||
f_eq("name", PartialValue::new_utf8s("claire")),
|
||||
f_eq("name", PartialValue::new_utf8s("william"))
|
||||
]),
|
||||
]))
|
||||
};
|
||||
let filt = filter_resolved!(f_and!([
|
||||
f_or!([
|
||||
f_eq("nonexist", PartialValue::new_utf8s("x")),
|
||||
f_eq("nonexist", PartialValue::new_utf8s("y"))
|
||||
]),
|
||||
f_or!([
|
||||
f_eq("name", PartialValue::new_utf8s("claire")),
|
||||
f_eq("name", PartialValue::new_utf8s("william"))
|
||||
]),
|
||||
]));
|
||||
|
||||
let res = be.search(&lim_allow, &filt);
|
||||
assert!(res.is_ok());
|
||||
|
@ -3375,14 +3342,14 @@ mod tests {
|
|||
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e.add_ava("userid", Value::from("william"));
|
||||
e.add_ava("uuid", Value::from("db237e8a-0079-4b8c-8a56-593b22aa44d1"));
|
||||
let e = unsafe { e.into_sealed_new() };
|
||||
let e = e.into_sealed_new();
|
||||
|
||||
let single_result = be_a_txn.create(&CID_ZERO, vec![e]);
|
||||
|
||||
assert!(single_result.is_ok());
|
||||
|
||||
// Assert it's in A but not B.
|
||||
let filt = unsafe { filter_resolved!(f_eq("userid", PartialValue::new_utf8s("william"))) };
|
||||
let filt = filter_resolved!(f_eq("userid", PartialValue::new_utf8s("william")));
|
||||
|
||||
let lims = Limits::unlimited();
|
||||
|
||||
|
@ -3396,14 +3363,14 @@ mod tests {
|
|||
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e.add_ava("userid", Value::from("claire"));
|
||||
e.add_ava("uuid", Value::from("0c680959-0944-47d6-9dea-53304d124266"));
|
||||
let e = unsafe { e.into_sealed_new() };
|
||||
let e = e.into_sealed_new();
|
||||
|
||||
let single_result = be_b_txn.create(&CID_ZERO, vec![e]);
|
||||
|
||||
assert!(single_result.is_ok());
|
||||
|
||||
// Assert it's in B but not A
|
||||
let filt = unsafe { filter_resolved!(f_eq("userid", PartialValue::new_utf8s("claire"))) };
|
||||
let filt = filter_resolved!(f_eq("userid", PartialValue::new_utf8s("claire")));
|
||||
|
||||
let lims = Limits::unlimited();
|
||||
|
||||
|
|
|
@ -522,12 +522,14 @@ impl Entry<EntryInit, EntryNew> {
|
|||
compare_attrs(&self.attrs, &rhs.attrs)
|
||||
}
|
||||
|
||||
/// ⚠️ This function bypasses the db commit and creates invalid replication metadata.
|
||||
/// The entry it creates can never be replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_invalid_new(mut self) -> Entry<EntryInvalid, EntryNew> {
|
||||
pub fn into_invalid_new(mut self) -> Entry<EntryInvalid, EntryNew> {
|
||||
let cid = Cid::new_zero();
|
||||
self.set_last_changed(cid.clone());
|
||||
|
||||
// let eclog = EntryChangelog::new_without_schema(cid.clone(), self.attrs.clone());
|
||||
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
|
||||
|
||||
Entry {
|
||||
|
@ -537,11 +539,13 @@ impl Entry<EntryInit, EntryNew> {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ This function bypasses the db commit and creates invalid replication metadata.
|
||||
/// The entry it creates can never be replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_valid_new(mut self) -> Entry<EntryValid, EntryNew> {
|
||||
pub fn into_valid_new(mut self) -> Entry<EntryValid, EntryNew> {
|
||||
let cid = Cid::new_zero();
|
||||
self.set_last_changed(cid.clone());
|
||||
// let eclog = EntryChangelog::new_without_schema(cid.clone(), self.attrs.clone());
|
||||
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
|
||||
|
||||
Entry {
|
||||
|
@ -554,11 +558,13 @@ impl Entry<EntryInit, EntryNew> {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ This function bypasses the db commit, assigns fake db ids, and invalid replication metadata.
|
||||
/// The entry it creates can never be committed safely or replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_sealed_committed(mut self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
pub fn into_sealed_committed(mut self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
let cid = Cid::new_zero();
|
||||
self.set_last_changed(cid.clone());
|
||||
// let eclog = EntryChangelog::new_without_schema(cid, self.attrs.clone());
|
||||
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
|
||||
let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
|
||||
Entry {
|
||||
|
@ -568,11 +574,13 @@ impl Entry<EntryInit, EntryNew> {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ This function bypasses the db commit and creates invalid replication metadata.
|
||||
/// The entry it creates can never be replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_sealed_new(mut self) -> Entry<EntrySealed, EntryNew> {
|
||||
pub fn into_sealed_new(mut self) -> Entry<EntrySealed, EntryNew> {
|
||||
let cid = Cid::new_zero();
|
||||
self.set_last_changed(cid.clone());
|
||||
// let eclog = EntryChangelog::new_without_schema(cid, self.attrs.clone());
|
||||
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
|
||||
|
||||
Entry {
|
||||
|
@ -1103,13 +1111,12 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* A series of unsafe transitions allowing entries to skip certain steps in
|
||||
* the process to facilitate eq/checks.
|
||||
*/
|
||||
impl Entry<EntryInvalid, EntryCommitted> {
|
||||
/// ⚠️ This function bypasses the schema validation and can panic if uuid is not found.
|
||||
/// The entry it creates can never be committed safely or replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
|
||||
pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
|
||||
let uuid = self.get_uuid().expect("Invalid uuid");
|
||||
Entry {
|
||||
valid: EntryValid {
|
||||
|
@ -1156,8 +1163,11 @@ impl Entry<EntryInvalid, EntryCommitted> {
|
|||
// Both invalid states can be reached from "entry -> invalidate"
|
||||
|
||||
impl Entry<EntryInvalid, EntryNew> {
|
||||
/// ⚠️ This function bypasses the schema validation and can panic if uuid is not found.
|
||||
/// The entry it creates can never be committed safely or replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
|
||||
pub fn into_valid_new(self) -> Entry<EntryValid, EntryNew> {
|
||||
let uuid = self.get_uuid().expect("Invalid uuid");
|
||||
Entry {
|
||||
valid: EntryValid {
|
||||
|
@ -1169,8 +1179,11 @@ impl Entry<EntryInvalid, EntryNew> {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ This function bypasses the db commit, assigns fake db ids, and assigns an invalid uuid.
|
||||
/// The entry it creates can never be committed safely or replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
|
||||
Entry {
|
||||
valid: EntrySealed {
|
||||
|
@ -1182,26 +1195,11 @@ impl Entry<EntryInvalid, EntryNew> {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// ⚠️ This function bypasses the schema validation and assigns a fake uuid.
|
||||
/// The entry it creates can never be committed safely or replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_valid_normal(self) -> Entry<EntryNormalised, EntryNew> {
|
||||
Entry {
|
||||
valid: EntryNormalised,
|
||||
state: EntryNew,
|
||||
attrs: self
|
||||
.attrs
|
||||
.into_iter()
|
||||
.map(|(k, mut v)| {
|
||||
v.sort_unstable();
|
||||
(k, v)
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_valid_committed(self) -> Entry<EntryValid, EntryCommitted> {
|
||||
pub fn into_valid_committed(self) -> Entry<EntryValid, EntryCommitted> {
|
||||
let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
|
||||
Entry {
|
||||
valid: EntryValid {
|
||||
|
@ -1215,8 +1213,11 @@ impl Entry<EntryInvalid, EntryNew> {
|
|||
}
|
||||
|
||||
impl Entry<EntryInvalid, EntryCommitted> {
|
||||
/// ⚠️ This function bypasses the schema validation and assigns a fake uuid.
|
||||
/// The entry it creates can never be committed safely or replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
let uuid = self.get_uuid().unwrap_or_else(Uuid::new_v4);
|
||||
Entry {
|
||||
valid: EntrySealed {
|
||||
|
@ -1230,8 +1231,11 @@ impl Entry<EntryInvalid, EntryCommitted> {
|
|||
}
|
||||
|
||||
impl Entry<EntrySealed, EntryNew> {
|
||||
/// ⚠️ This function bypasses schema validation and assigns an invalid uuid.
|
||||
/// The entry it creates can never be committed safely or replicated.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
Entry {
|
||||
valid: self.valid,
|
||||
state: EntryCommitted { id: 0 },
|
||||
|
@ -1280,8 +1284,9 @@ impl Entry<EntrySealed, EntryCommitted> {
|
|||
self.valid.ecstate.get_tail_cid()
|
||||
}
|
||||
|
||||
/// State transititon to allow self to self for certain test macros.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
pub fn into_sealed_committed(self) -> Entry<EntrySealed, EntryCommitted> {
|
||||
// NO-OP to satisfy macros.
|
||||
self
|
||||
}
|
||||
|
@ -1782,13 +1787,15 @@ impl Entry<EntrySealed, EntryCommitted> {
|
|||
})
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// This function bypasses the access control validation logic and should NOT
|
||||
/// ⚠️ This function bypasses the access control validation logic and should NOT
|
||||
/// be used without special care and attention to ensure that no private data
|
||||
/// is leaked incorrectly to clients. Generally this is ONLY used inside of
|
||||
/// the access control processing functions which correctly applies the reduction
|
||||
/// steps.
|
||||
pub unsafe fn into_reduced(self) -> Entry<EntryReduced, EntryCommitted> {
|
||||
///
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub(crate) fn into_reduced(self) -> Entry<EntryReduced, EntryCommitted> {
|
||||
Entry {
|
||||
valid: EntryReduced {
|
||||
uuid: self.valid.uuid,
|
||||
|
@ -2169,12 +2176,14 @@ where
|
|||
&self.valid.ecstate
|
||||
}
|
||||
|
||||
/// ⚠️ - Invalidate an entry by resetting it's change state to time-zero. This entry
|
||||
/// can never be replicated after this.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_invalid(mut self) -> Entry<EntryInvalid, STATE> {
|
||||
pub(crate) fn into_invalid(mut self) -> Entry<EntryInvalid, STATE> {
|
||||
let cid = Cid::new_zero();
|
||||
self.set_last_changed(cid.clone());
|
||||
|
||||
// let eclog = EntryChangelog::new_without_schema(cid.clone(), self.attrs.clone());
|
||||
let ecstate = EntryChangeState::new_without_schema(&cid, &self.attrs);
|
||||
|
||||
Entry {
|
||||
|
@ -3201,16 +3210,14 @@ mod tests {
|
|||
#[test]
|
||||
fn test_entry_apply_modlist() {
|
||||
// Test application of changes to an entry.
|
||||
let mut e: Entry<EntryInvalid, EntryNew> = unsafe { Entry::new().into_invalid_new() };
|
||||
let mut e: Entry<EntryInvalid, EntryNew> = Entry::new().into_invalid_new();
|
||||
|
||||
e.add_ava("userid", Value::from("william"));
|
||||
|
||||
let present_single_mods = unsafe {
|
||||
ModifyList::new_valid_list(vec![Modify::Present(
|
||||
AttrString::from("attr"),
|
||||
Value::new_iutf8("value"),
|
||||
)])
|
||||
};
|
||||
let present_single_mods = ModifyList::new_valid_list(vec![Modify::Present(
|
||||
AttrString::from("attr"),
|
||||
Value::new_iutf8("value"),
|
||||
)]);
|
||||
|
||||
assert!(e.apply_modlist(&present_single_mods).is_ok());
|
||||
|
||||
|
@ -3219,12 +3226,10 @@ mod tests {
|
|||
assert!(e.attribute_equality("attr", &PartialValue::new_iutf8("value")));
|
||||
|
||||
// Assert present for multivalue
|
||||
let present_multivalue_mods = unsafe {
|
||||
ModifyList::new_valid_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_iutf8("test")),
|
||||
Modify::Present(AttrString::from("class"), Value::new_iutf8("multi_test")),
|
||||
])
|
||||
};
|
||||
let present_multivalue_mods = ModifyList::new_valid_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_iutf8("test")),
|
||||
Modify::Present(AttrString::from("class"), Value::new_iutf8("multi_test")),
|
||||
]);
|
||||
|
||||
assert!(e.apply_modlist(&present_multivalue_mods).is_ok());
|
||||
|
||||
|
@ -3233,14 +3238,14 @@ mod tests {
|
|||
|
||||
// Assert purge on single/multi/empty value
|
||||
let purge_single_mods =
|
||||
unsafe { ModifyList::new_valid_list(vec![Modify::Purged(AttrString::from("attr"))]) };
|
||||
ModifyList::new_valid_list(vec![Modify::Purged(AttrString::from("attr"))]);
|
||||
|
||||
assert!(e.apply_modlist(&purge_single_mods).is_ok());
|
||||
|
||||
assert!(!e.attribute_pres("attr"));
|
||||
|
||||
let purge_multi_mods =
|
||||
unsafe { ModifyList::new_valid_list(vec![Modify::Purged(AttrString::from("class"))]) };
|
||||
ModifyList::new_valid_list(vec![Modify::Purged(AttrString::from("class"))]);
|
||||
|
||||
assert!(e.apply_modlist(&purge_multi_mods).is_ok());
|
||||
|
||||
|
@ -3251,12 +3256,10 @@ mod tests {
|
|||
assert!(e.apply_modlist(&purge_empty_mods).is_ok());
|
||||
|
||||
// Assert removed on value that exists and doesn't exist
|
||||
let remove_mods = unsafe {
|
||||
ModifyList::new_valid_list(vec![Modify::Removed(
|
||||
AttrString::from("attr"),
|
||||
PartialValue::new_iutf8("value"),
|
||||
)])
|
||||
};
|
||||
let remove_mods = ModifyList::new_valid_list(vec![Modify::Removed(
|
||||
AttrString::from("attr"),
|
||||
PartialValue::new_iutf8("value"),
|
||||
)]);
|
||||
|
||||
assert!(e.apply_modlist(&present_single_mods).is_ok());
|
||||
assert!(e.attribute_equality("attr", &PartialValue::new_iutf8("value")));
|
||||
|
@ -3277,12 +3280,12 @@ mod tests {
|
|||
let mut e1_mod = e1.clone();
|
||||
e1_mod.add_ava("extra", Value::from("test"));
|
||||
|
||||
let e1 = unsafe { e1.into_sealed_committed() };
|
||||
let e1_mod = unsafe { e1_mod.into_sealed_committed() };
|
||||
let e1 = e1.into_sealed_committed();
|
||||
let e1_mod = e1_mod.into_sealed_committed();
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("userid", Value::from("claire"));
|
||||
let e2 = unsafe { e2.into_sealed_committed() };
|
||||
let e2 = e2.into_sealed_committed();
|
||||
|
||||
let mut idxmeta = HashMap::with_capacity(8);
|
||||
idxmeta.insert(
|
||||
|
@ -3409,18 +3412,18 @@ mod tests {
|
|||
fn test_entry_mask_recycled_ts() {
|
||||
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e1.add_ava("class", Value::new_class("person"));
|
||||
let e1 = unsafe { e1.into_sealed_committed() };
|
||||
let e1 = e1.into_sealed_committed();
|
||||
assert!(e1.mask_recycled_ts().is_some());
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("class", Value::new_class("person"));
|
||||
e2.add_ava("class", Value::new_class("recycled"));
|
||||
let e2 = unsafe { e2.into_sealed_committed() };
|
||||
let e2 = e2.into_sealed_committed();
|
||||
assert!(e2.mask_recycled_ts().is_none());
|
||||
|
||||
let mut e3: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e3.add_ava("class", Value::new_class("tombstone"));
|
||||
let e3 = unsafe { e3.into_sealed_committed() };
|
||||
let e3 = e3.into_sealed_committed();
|
||||
assert!(e3.mask_recycled_ts().is_none());
|
||||
}
|
||||
|
||||
|
@ -3434,7 +3437,7 @@ mod tests {
|
|||
{
|
||||
let mut e: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e.add_ava("class", Value::new_class("person"));
|
||||
let e = unsafe { e.into_sealed_committed() };
|
||||
let e = e.into_sealed_committed();
|
||||
|
||||
assert!(Entry::idx_name2uuid_diff(None, Some(&e)) == (Some(Set::new()), None));
|
||||
}
|
||||
|
@ -3449,7 +3452,7 @@ mod tests {
|
|||
"uuid",
|
||||
Value::Uuid(uuid!("9fec0398-c46c-4df4-9df5-b0016f7d563f")),
|
||||
);
|
||||
let e = unsafe { e.into_sealed_committed() };
|
||||
let e = e.into_sealed_committed();
|
||||
|
||||
// Note the uuid isn't present!
|
||||
assert!(
|
||||
|
@ -3489,13 +3492,13 @@ mod tests {
|
|||
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e1.add_ava("class", Value::new_class("person"));
|
||||
e1.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
|
||||
let e1 = unsafe { e1.into_sealed_committed() };
|
||||
let e1 = e1.into_sealed_committed();
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("class", Value::new_class("person"));
|
||||
e2.add_ava("name", Value::new_iname("testperson"));
|
||||
e2.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
|
||||
let e2 = unsafe { e2.into_sealed_committed() };
|
||||
let e2 = e2.into_sealed_committed();
|
||||
|
||||
// One attr added
|
||||
assert!(
|
||||
|
@ -3515,12 +3518,12 @@ mod tests {
|
|||
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e1.add_ava("class", Value::new_class("person"));
|
||||
e1.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
|
||||
let e1 = unsafe { e1.into_sealed_committed() };
|
||||
let e1 = e1.into_sealed_committed();
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("class", Value::new_class("person"));
|
||||
e2.add_ava("spn", Value::new_spn_str("renameperson", "example.com"));
|
||||
let e2 = unsafe { e2.into_sealed_committed() };
|
||||
let e2 = e2.into_sealed_committed();
|
||||
|
||||
assert!(
|
||||
Entry::idx_name2uuid_diff(Some(&e1), Some(&e2))
|
||||
|
@ -3538,11 +3541,11 @@ mod tests {
|
|||
|
||||
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e1.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
|
||||
let e1 = unsafe { e1.into_sealed_committed() };
|
||||
let e1 = e1.into_sealed_committed();
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("spn", Value::new_spn_str("renameperson", "example.com"));
|
||||
let e2 = unsafe { e2.into_sealed_committed() };
|
||||
let e2 = e2.into_sealed_committed();
|
||||
|
||||
assert!(
|
||||
Entry::idx_uuid2spn_diff(None, Some(&e1))
|
||||
|
@ -3562,11 +3565,11 @@ mod tests {
|
|||
|
||||
let mut e1: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e1.add_ava("spn", Value::new_spn_str("testperson", "example.com"));
|
||||
let e1 = unsafe { e1.into_sealed_committed() };
|
||||
let e1 = e1.into_sealed_committed();
|
||||
|
||||
let mut e2: Entry<EntryInit, EntryNew> = Entry::new();
|
||||
e2.add_ava("spn", Value::new_spn_str("renameperson", "example.com"));
|
||||
let e2 = unsafe { e2.into_sealed_committed() };
|
||||
let e2 = e2.into_sealed_committed();
|
||||
|
||||
assert!(
|
||||
Entry::idx_uuid2rdn_diff(None, Some(&e1))
|
||||
|
|
|
@ -200,9 +200,11 @@ impl SearchEvent {
|
|||
})
|
||||
}
|
||||
|
||||
// Just impersonate the account with no filter changes.
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_entry_ser(e: &str, filter: Filter<FilterInvalid>) -> Self {
|
||||
pub fn new_impersonate_entry_ser(e: &str, filter: Filter<FilterInvalid>) -> Self {
|
||||
// Just impersonate the account with no filter changes.
|
||||
let ei: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(e);
|
||||
SearchEvent {
|
||||
ident: Identity::from_impersonate_entry_readonly(Arc::new(ei.into_sealed_committed())),
|
||||
|
@ -212,8 +214,10 @@ impl SearchEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_entry(
|
||||
pub fn new_impersonate_entry(
|
||||
e: Arc<Entry<EntrySealed, EntryCommitted>>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
) -> Self {
|
||||
|
@ -225,8 +229,10 @@ impl SearchEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_identity(ident: Identity, filter: Filter<FilterInvalid>) -> Self {
|
||||
pub fn new_impersonate_identity(ident: Identity, filter: Filter<FilterInvalid>) -> Self {
|
||||
SearchEvent {
|
||||
ident,
|
||||
filter: filter.clone().into_valid(),
|
||||
|
@ -248,12 +254,14 @@ impl SearchEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
/* Impersonate a request for recycled objects */
|
||||
pub unsafe fn new_rec_impersonate_entry(
|
||||
pub fn new_rec_impersonate_entry(
|
||||
e: Arc<Entry<EntrySealed, EntryCommitted>>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
) -> Self {
|
||||
/* Impersonate a request for recycled objects */
|
||||
let filter_orig = filter.into_valid();
|
||||
let filter = filter_orig.clone().into_recycled();
|
||||
SearchEvent {
|
||||
|
@ -264,12 +272,14 @@ impl SearchEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
/* Impersonate an external request AKA filter ts + recycle */
|
||||
pub unsafe fn new_ext_impersonate_entry(
|
||||
pub fn new_ext_impersonate_entry(
|
||||
e: Arc<Entry<EntrySealed, EntryCommitted>>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
) -> Self {
|
||||
/* Impersonate an external request AKA filter ts + recycle */
|
||||
SearchEvent {
|
||||
ident: Identity::from_impersonate_entry_readonly(e),
|
||||
filter: filter.clone().into_valid().into_ignore_hidden(),
|
||||
|
@ -298,8 +308,10 @@ impl SearchEvent {
|
|||
})
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
|
||||
pub fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
|
||||
SearchEvent {
|
||||
ident: Identity::from_internal(),
|
||||
filter: filter.clone().into_valid(),
|
||||
|
@ -355,11 +367,10 @@ impl CreateEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Use an unsafe entry impersonation method.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_entry_ser(
|
||||
e: &str,
|
||||
entries: Vec<Entry<EntryInit, EntryNew>>,
|
||||
) -> Self {
|
||||
pub fn new_impersonate_entry_ser(e: &str, entries: Vec<Entry<EntryInit, EntryNew>>) -> Self {
|
||||
let ei: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(e);
|
||||
CreateEvent {
|
||||
ident: Identity::from_impersonate_entry_readwrite(Arc::new(ei.into_sealed_committed())),
|
||||
|
@ -401,9 +412,10 @@ impl ExistsEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
#[allow(dead_code)]
|
||||
pub unsafe fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
|
||||
pub fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
|
||||
ExistsEvent {
|
||||
ident: Identity::from_internal(),
|
||||
filter: filter.clone().into_valid(),
|
||||
|
@ -459,8 +471,10 @@ impl DeleteEvent {
|
|||
})
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_entry(
|
||||
pub fn new_impersonate_entry(
|
||||
e: Arc<Entry<EntrySealed, EntryCommitted>>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
) -> Self {
|
||||
|
@ -471,19 +485,21 @@ impl DeleteEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine, allowing an invalid filter to be used in an impersonate request.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub fn new_impersonate_identity(ident: Identity, filter: Filter<FilterInvalid>) -> Self {
|
||||
unsafe {
|
||||
DeleteEvent {
|
||||
ident,
|
||||
filter: filter.clone().into_valid(),
|
||||
filter_orig: filter.into_valid(),
|
||||
}
|
||||
DeleteEvent {
|
||||
ident,
|
||||
filter: filter.clone().into_valid(),
|
||||
filter_orig: filter.into_valid(),
|
||||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_entry_ser(e: &str, filter: Filter<FilterInvalid>) -> Self {
|
||||
pub fn new_impersonate_entry_ser(e: &str, filter: Filter<FilterInvalid>) -> Self {
|
||||
let ei: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str(e);
|
||||
DeleteEvent {
|
||||
ident: Identity::from_impersonate_entry_readwrite(Arc::new(ei.into_sealed_committed())),
|
||||
|
@ -492,8 +508,10 @@ impl DeleteEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
|
||||
pub fn new_internal_invalid(filter: Filter<FilterInvalid>) -> Self {
|
||||
DeleteEvent {
|
||||
ident: Identity::from_internal(),
|
||||
filter: filter.clone().into_valid(),
|
||||
|
@ -629,8 +647,10 @@ impl ModifyEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_internal_invalid(
|
||||
pub fn new_internal_invalid(
|
||||
filter: Filter<FilterInvalid>,
|
||||
modlist: ModifyList<ModifyInvalid>,
|
||||
) -> Self {
|
||||
|
@ -642,8 +662,10 @@ impl ModifyEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_entry_ser(
|
||||
pub fn new_impersonate_entry_ser(
|
||||
e: &str,
|
||||
filter: Filter<FilterInvalid>,
|
||||
modlist: ModifyList<ModifyInvalid>,
|
||||
|
@ -657,8 +679,10 @@ impl ModifyEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_identity(
|
||||
pub fn new_impersonate_identity(
|
||||
ident: Identity,
|
||||
filter: Filter<FilterInvalid>,
|
||||
modlist: ModifyList<ModifyInvalid>,
|
||||
|
@ -671,8 +695,10 @@ impl ModifyEvent {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_entry(
|
||||
pub fn new_impersonate_entry(
|
||||
e: Arc<Entry<EntrySealed, EntryCommitted>>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
modlist: ModifyList<ModifyInvalid>,
|
||||
|
@ -808,8 +834,10 @@ impl ReviveRecycledEvent {
|
|||
Ok(ReviveRecycledEvent { ident, filter })
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_impersonate_entry(
|
||||
pub fn new_impersonate_entry(
|
||||
e: Arc<Entry<EntrySealed, EntryCommitted>>,
|
||||
filter: Filter<FilterInvalid>,
|
||||
) -> Self {
|
||||
|
|
|
@ -412,8 +412,10 @@ impl Filter<FilterInvalid> {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_valid_resolved(self) -> Filter<FilterValidResolved> {
|
||||
pub fn into_valid_resolved(self) -> Filter<FilterValidResolved> {
|
||||
// There is a good reason this function only exists in tests ...
|
||||
//
|
||||
// YOLO.
|
||||
|
@ -449,8 +451,10 @@ impl Filter<FilterInvalid> {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Bypass the schema state machine and force the filter to be considered valid.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn into_valid(self) -> Filter<FilterValid> {
|
||||
pub fn into_valid(self) -> Filter<FilterValid> {
|
||||
// There is a good reason this function only exists in tests ...
|
||||
//
|
||||
// YOLO.
|
||||
|
@ -464,8 +468,10 @@ impl Filter<FilterInvalid> {
|
|||
}
|
||||
}
|
||||
|
||||
/// ⚠️ - Blindly accept a filter from a string, panicking if it fails to parse.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn from_str(fc: &str) -> Self {
|
||||
pub fn from_str(fc: &str) -> Self {
|
||||
let f: FC = serde_json::from_str(fc).expect("Failure parsing filter!");
|
||||
Filter {
|
||||
state: FilterInvalid {
|
||||
|
@ -1007,8 +1013,10 @@ impl Ord for FilterResolved {
|
|||
}
|
||||
|
||||
impl FilterResolved {
|
||||
/// ⚠️ - Process a filter without verifying with schema.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
unsafe fn from_invalid(fc: FilterComp, idxmeta: &HashSet<(&AttrString, &IndexType)>) -> Self {
|
||||
fn from_invalid(fc: FilterComp, idxmeta: &HashSet<(&AttrString, &IndexType)>) -> Self {
|
||||
match fc {
|
||||
FilterComp::Eq(a, v) => {
|
||||
let idx = idxmeta.contains(&(&a, &IndexType::Equality));
|
||||
|
@ -1378,9 +1386,9 @@ mod tests {
|
|||
let f_init: Filter<FilterInvalid> = Filter::new($init);
|
||||
let f_expect: Filter<FilterInvalid> = Filter::new($expect);
|
||||
// Create a resolved filter, via the most unsafe means possible!
|
||||
let f_init_r = unsafe { f_init.into_valid_resolved() };
|
||||
let f_init_r = f_init.into_valid_resolved();
|
||||
let f_init_o = f_init_r.optimise();
|
||||
let f_init_e = unsafe { f_expect.into_valid_resolved() };
|
||||
let f_init_e = f_expect.into_valid_resolved();
|
||||
debug!("--");
|
||||
debug!("init --> {:?}", f_init_r);
|
||||
debug!("opt --> {:?}", f_init_o);
|
||||
|
@ -1513,25 +1521,25 @@ mod tests {
|
|||
// Test that we uphold the rules of partialOrd
|
||||
// Basic equality
|
||||
// Test the two major paths here (str vs list)
|
||||
let f_t1a = unsafe { filter_resolved!(f_pres("userid")) };
|
||||
let f_t1b = unsafe { filter_resolved!(f_pres("userid")) };
|
||||
let f_t1a = filter_resolved!(f_pres("userid"));
|
||||
let f_t1b = filter_resolved!(f_pres("userid"));
|
||||
|
||||
assert_eq!(f_t1a.partial_cmp(&f_t1b), Some(Ordering::Equal));
|
||||
assert_eq!(f_t1b.partial_cmp(&f_t1a), Some(Ordering::Equal));
|
||||
|
||||
let f_t2a = unsafe { filter_resolved!(f_and!([])) };
|
||||
let f_t2b = unsafe { filter_resolved!(f_and!([])) };
|
||||
let f_t2a = filter_resolved!(f_and!([]));
|
||||
let f_t2b = filter_resolved!(f_and!([]));
|
||||
assert_eq!(f_t2a.partial_cmp(&f_t2b), Some(Ordering::Equal));
|
||||
assert_eq!(f_t2b.partial_cmp(&f_t2a), Some(Ordering::Equal));
|
||||
|
||||
// antisymmetry: if a < b then !(a > b), as well as a > b implying !(a < b); and
|
||||
// These are unindexed so we have to check them this way.
|
||||
let f_t3b = unsafe { filter_resolved!(f_eq("userid", PartialValue::new_iutf8(""))) };
|
||||
let f_t3b = filter_resolved!(f_eq("userid", PartialValue::new_iutf8("")));
|
||||
assert_eq!(f_t1a.partial_cmp(&f_t3b), Some(Ordering::Greater));
|
||||
assert_eq!(f_t3b.partial_cmp(&f_t1a), Some(Ordering::Less));
|
||||
|
||||
// transitivity: a < b and b < c implies a < c. The same must hold for both == and >.
|
||||
let f_t4b = unsafe { filter_resolved!(f_sub("userid", PartialValue::new_iutf8(""))) };
|
||||
let f_t4b = filter_resolved!(f_sub("userid", PartialValue::new_iutf8("")));
|
||||
assert_eq!(f_t1a.partial_cmp(&f_t4b), Some(Ordering::Less));
|
||||
assert_eq!(f_t3b.partial_cmp(&f_t4b), Some(Ordering::Less));
|
||||
|
||||
|
@ -1543,16 +1551,16 @@ mod tests {
|
|||
fn test_filter_clone() {
|
||||
// Test that cloning filters yields the same result regardless of
|
||||
// complexity.
|
||||
let f_t1a = unsafe { filter_resolved!(f_pres("userid")) };
|
||||
let f_t1a = filter_resolved!(f_pres("userid"));
|
||||
let f_t1b = f_t1a.clone();
|
||||
let f_t1c = unsafe { filter_resolved!(f_pres("zzzz")) };
|
||||
let f_t1c = filter_resolved!(f_pres("zzzz"));
|
||||
|
||||
assert!(f_t1a == f_t1b);
|
||||
assert!(f_t1a != f_t1c);
|
||||
|
||||
let f_t2a = unsafe { filter_resolved!(f_and!([f_pres("userid")])) };
|
||||
let f_t2a = filter_resolved!(f_and!([f_pres("userid")]));
|
||||
let f_t2b = f_t2a.clone();
|
||||
let f_t2c = unsafe { filter_resolved!(f_and!([f_pres("zzzz")])) };
|
||||
let f_t2c = filter_resolved!(f_and!([f_pres("zzzz")]));
|
||||
|
||||
assert!(f_t2a == f_t2b);
|
||||
assert!(f_t2a != f_t2c);
|
||||
|
@ -1560,205 +1568,168 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_lessthan_entry_filter() {
|
||||
let e = unsafe {
|
||||
entry_init!(
|
||||
("userid", Value::new_iutf8("william")),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new()
|
||||
};
|
||||
let e = entry_init!(
|
||||
("userid", Value::new_iutf8("william")),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new();
|
||||
|
||||
let f_t1a = unsafe { filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(500))) };
|
||||
let f_t1a = filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(500)));
|
||||
assert!(!e.entry_match_no_index(&f_t1a));
|
||||
|
||||
let f_t1b = unsafe { filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(1000))) };
|
||||
let f_t1b = filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(1000)));
|
||||
assert!(!e.entry_match_no_index(&f_t1b));
|
||||
|
||||
let f_t1c = unsafe { filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(1001))) };
|
||||
let f_t1c = filter_resolved!(f_lt("gidnumber", PartialValue::new_uint32(1001)));
|
||||
assert!(e.entry_match_no_index(&f_t1c));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_or_entry_filter() {
|
||||
let e = unsafe {
|
||||
entry_init!(
|
||||
("userid", Value::new_iutf8("william")),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new()
|
||||
};
|
||||
let e = entry_init!(
|
||||
("userid", Value::new_iutf8("william")),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new();
|
||||
|
||||
let f_t1a = unsafe {
|
||||
filter_resolved!(f_or!([
|
||||
f_eq("userid", PartialValue::new_iutf8("william")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]))
|
||||
};
|
||||
let f_t1a = filter_resolved!(f_or!([
|
||||
f_eq("userid", PartialValue::new_iutf8("william")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]));
|
||||
assert!(e.entry_match_no_index(&f_t1a));
|
||||
|
||||
let f_t2a = unsafe {
|
||||
filter_resolved!(f_or!([
|
||||
f_eq("userid", PartialValue::new_iutf8("william")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]))
|
||||
};
|
||||
let f_t2a = filter_resolved!(f_or!([
|
||||
f_eq("userid", PartialValue::new_iutf8("william")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]));
|
||||
assert!(e.entry_match_no_index(&f_t2a));
|
||||
|
||||
let f_t3a = unsafe {
|
||||
filter_resolved!(f_or!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]))
|
||||
};
|
||||
let f_t3a = filter_resolved!(f_or!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]));
|
||||
assert!(e.entry_match_no_index(&f_t3a));
|
||||
|
||||
let f_t4a = unsafe {
|
||||
filter_resolved!(f_or!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1001)),
|
||||
]))
|
||||
};
|
||||
let f_t4a = filter_resolved!(f_or!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1001)),
|
||||
]));
|
||||
assert!(!e.entry_match_no_index(&f_t4a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_and_entry_filter() {
|
||||
let e = unsafe {
|
||||
entry_init!(
|
||||
("userid", Value::new_iutf8("william")),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new()
|
||||
};
|
||||
let e = entry_init!(
|
||||
("userid", Value::new_iutf8("william")),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new();
|
||||
|
||||
let f_t1a = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("william")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]))
|
||||
};
|
||||
let f_t1a = filter_resolved!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("william")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]));
|
||||
assert!(e.entry_match_no_index(&f_t1a));
|
||||
|
||||
let f_t2a = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("william")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1001)),
|
||||
]))
|
||||
};
|
||||
let f_t2a = filter_resolved!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("william")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1001)),
|
||||
]));
|
||||
assert!(!e.entry_match_no_index(&f_t2a));
|
||||
|
||||
let f_t3a = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]))
|
||||
};
|
||||
let f_t3a = filter_resolved!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000)),
|
||||
]));
|
||||
assert!(!e.entry_match_no_index(&f_t3a));
|
||||
|
||||
let f_t4a = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1001)),
|
||||
]))
|
||||
};
|
||||
let f_t4a = filter_resolved!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1001)),
|
||||
]));
|
||||
assert!(!e.entry_match_no_index(&f_t4a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_not_entry_filter() {
|
||||
let e1 = unsafe {
|
||||
entry_init!(
|
||||
("userid", Value::new_iutf8("william")),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new()
|
||||
};
|
||||
let e1 = entry_init!(
|
||||
("userid", Value::new_iutf8("william")),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new();
|
||||
|
||||
let f_t1a =
|
||||
unsafe { filter_resolved!(f_andnot(f_eq("userid", PartialValue::new_iutf8("alice")))) };
|
||||
let f_t1a = filter_resolved!(f_andnot(f_eq("userid", PartialValue::new_iutf8("alice"))));
|
||||
assert!(e1.entry_match_no_index(&f_t1a));
|
||||
|
||||
let f_t2a = unsafe {
|
||||
filter_resolved!(f_andnot(f_eq("userid", PartialValue::new_iutf8("william"))))
|
||||
};
|
||||
let f_t2a = filter_resolved!(f_andnot(f_eq("userid", PartialValue::new_iutf8("william"))));
|
||||
assert!(!e1.entry_match_no_index(&f_t2a));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nested_entry_filter() {
|
||||
let e1 = unsafe {
|
||||
entry_init!(
|
||||
("class", CLASS_PERSON.clone()),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new()
|
||||
};
|
||||
let e1 = entry_init!(
|
||||
("class", CLASS_PERSON.clone()),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new();
|
||||
|
||||
let e2 = unsafe {
|
||||
entry_init!(
|
||||
("class", CLASS_PERSON.clone()),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("4b6228ab-1dbe-42a4-a9f5-f6368222438e"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1001))
|
||||
)
|
||||
.into_sealed_new()
|
||||
};
|
||||
let e2 = entry_init!(
|
||||
("class", CLASS_PERSON.clone()),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("4b6228ab-1dbe-42a4-a9f5-f6368222438e"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1001))
|
||||
)
|
||||
.into_sealed_new();
|
||||
|
||||
let e3 = unsafe {
|
||||
entry_init!(
|
||||
("class", CLASS_PERSON.clone()),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("7b23c99d-c06b-4a9a-a958-3afa56383e1d"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1002))
|
||||
)
|
||||
.into_sealed_new()
|
||||
};
|
||||
let e3 = entry_init!(
|
||||
("class", CLASS_PERSON.clone()),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("7b23c99d-c06b-4a9a-a958-3afa56383e1d"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1002))
|
||||
)
|
||||
.into_sealed_new();
|
||||
|
||||
let e4 = unsafe {
|
||||
entry_init!(
|
||||
("class", CLASS_GROUP.clone()),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("21d816b5-1f6a-4696-b7c1-6ed06d22ed81"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new()
|
||||
};
|
||||
let e4 = entry_init!(
|
||||
("class", CLASS_GROUP.clone()),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("21d816b5-1f6a-4696-b7c1-6ed06d22ed81"))
|
||||
),
|
||||
("gidnumber", Value::Uint32(1000))
|
||||
)
|
||||
.into_sealed_new();
|
||||
|
||||
let f_t1a = unsafe {
|
||||
filter_resolved!(f_and!([
|
||||
f_eq("class", PVCLASS_PERSON.clone()),
|
||||
f_or!([
|
||||
f_eq("gidnumber", PartialValue::Uint32(1001)),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000))
|
||||
])
|
||||
]))
|
||||
};
|
||||
let f_t1a = filter_resolved!(f_and!([
|
||||
f_eq("class", PVCLASS_PERSON.clone()),
|
||||
f_or!([
|
||||
f_eq("gidnumber", PartialValue::Uint32(1001)),
|
||||
f_eq("gidnumber", PartialValue::Uint32(1000))
|
||||
])
|
||||
]));
|
||||
|
||||
assert!(e1.entry_match_no_index(&f_t1a));
|
||||
assert!(e2.entry_match_no_index(&f_t1a));
|
||||
|
@ -1773,22 +1744,18 @@ mod tests {
|
|||
f_expect.insert("class");
|
||||
// Given filters, get their expected attribute sets - this is used by access control profiles
|
||||
// to determine what attrs we are requesting regardless of the partialvalue.
|
||||
let f_t1a = unsafe {
|
||||
filter_valid!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("class", PartialValue::new_iutf8("1001")),
|
||||
]))
|
||||
};
|
||||
let f_t1a = filter_valid!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("class", PartialValue::new_iutf8("1001")),
|
||||
]));
|
||||
|
||||
assert!(f_t1a.get_attr_set() == f_expect);
|
||||
|
||||
let f_t2a = unsafe {
|
||||
filter_valid!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("class", PartialValue::new_iutf8("1001")),
|
||||
f_eq("userid", PartialValue::new_iutf8("claire")),
|
||||
]))
|
||||
};
|
||||
let f_t2a = filter_valid!(f_and!([
|
||||
f_eq("userid", PartialValue::new_iutf8("alice")),
|
||||
f_eq("class", PartialValue::new_iutf8("1001")),
|
||||
f_eq("userid", PartialValue::new_iutf8("claire")),
|
||||
]));
|
||||
|
||||
assert!(f_t2a.get_attr_set() == f_expect);
|
||||
}
|
||||
|
@ -1843,12 +1810,10 @@ mod tests {
|
|||
let cr = server_txn.create(&ce);
|
||||
assert!(cr.is_ok());
|
||||
|
||||
let de_sin = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson3")
|
||||
)])))
|
||||
};
|
||||
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson3")
|
||||
)])));
|
||||
assert!(server_txn.delete(&de_sin).is_ok());
|
||||
|
||||
// Commit
|
||||
|
|
|
@ -821,15 +821,13 @@ mod tests {
|
|||
assert!(uat.ui_hints.contains(&UiHint::CredentialUpdate));
|
||||
|
||||
// Modify the user to be a posix account, ensure they get the hint.
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testaccount"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_posix = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testaccount"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||
|
||||
// Check the ui hints are as expected.
|
||||
|
|
|
@ -5,12 +5,9 @@ use kanidm_proto::internal::AppLink;
|
|||
impl<'a> IdmServerProxyReadTransaction<'a> {
|
||||
pub fn list_applinks(&mut self, ident: &Identity) -> Result<Vec<AppLink>, OperationError> {
|
||||
// From the member-of of the ident.
|
||||
let ident_mo = match ident.get_memberof() {
|
||||
Some(mo) => mo,
|
||||
None => {
|
||||
debug!("Ident has no memberof, no applinks are present");
|
||||
return Ok(Vec::with_capacity(0));
|
||||
}
|
||||
let Some(ident_mo) = ident.get_memberof() else {
|
||||
debug!("Ident has no memberof, no applinks are present");
|
||||
return Ok(Vec::with_capacity(0));
|
||||
};
|
||||
|
||||
// Formerly we did an internal search here, but we no longer need to since we have
|
||||
|
@ -143,12 +140,10 @@ mod tests {
|
|||
|
||||
// Add them to the group.
|
||||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
let me_inv_m = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("uuid", PartialValue::Refer(grp_uuid))),
|
||||
ModifyList::new_append("member", Value::Refer(usr_uuid)),
|
||||
)
|
||||
};
|
||||
let me_inv_m = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("uuid", PartialValue::Refer(grp_uuid))),
|
||||
ModifyList::new_append("member", Value::Refer(usr_uuid)),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ use crate::prelude::*;
|
|||
use kanidm_proto::v1::OperationError;
|
||||
use kanidm_proto::v1::{AuthCredential, AuthIssueSession, AuthMech, AuthRequest, AuthStep};
|
||||
|
||||
#[cfg(test)]
|
||||
use std::sync::Arc;
|
||||
#[cfg(test)]
|
||||
use webauthn_rs::prelude::PublicKeyCredential;
|
||||
|
||||
|
@ -109,8 +111,8 @@ impl RadiusAuthTokenEvent {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn new_internal(target: Uuid) -> Self {
|
||||
let ident = Identity::from_internal();
|
||||
pub fn new_impersonate(e: Arc<Entry<EntrySealed, EntryCommitted>>, target: Uuid) -> Self {
|
||||
let ident = Identity::from_impersonate_entry_readonly(e);
|
||||
|
||||
RadiusAuthTokenEvent { ident, target }
|
||||
}
|
||||
|
@ -155,8 +157,8 @@ impl UnixGroupTokenEvent {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn new_internal(target: Uuid) -> Self {
|
||||
let ident = Identity::from_internal();
|
||||
pub fn new_impersonate(e: Arc<Entry<EntrySealed, EntryCommitted>>, target: Uuid) -> Self {
|
||||
let ident = Identity::from_impersonate_entry_readonly(e);
|
||||
|
||||
UnixGroupTokenEvent { ident, target }
|
||||
}
|
||||
|
|
|
@ -624,15 +624,13 @@ mod tests {
|
|||
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
// make the admin a valid posix account
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_posix = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||
|
||||
let pce = UnixPasswordChangeEvent::new_internal(UUID_ADMIN, TEST_PASSWORD);
|
||||
|
@ -1010,18 +1008,16 @@ mod tests {
|
|||
assert!(server_txn.qs_write.create(&ce).is_ok());
|
||||
|
||||
// idm_people_read_priv
|
||||
let me = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("idm_people_read_priv")
|
||||
)),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("member"),
|
||||
Value::Refer(sa_uuid),
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("idm_people_read_priv")
|
||||
)),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("member"),
|
||||
Value::Refer(sa_uuid),
|
||||
)]),
|
||||
);
|
||||
assert!(server_txn.qs_write.modify(&me).is_ok());
|
||||
|
||||
// Issue a token
|
||||
|
@ -1206,15 +1202,13 @@ mod tests {
|
|||
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
// make the admin a valid posix account
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("uuid", PartialValue::Uuid(UUID_DOMAIN_INFO))),
|
||||
ModifyList::new_purge_and_set(
|
||||
"domain_ldap_basedn",
|
||||
Value::new_iutf8("o=kanidmproject"),
|
||||
),
|
||||
)
|
||||
};
|
||||
let me_posix = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("uuid", PartialValue::Uuid(UUID_DOMAIN_INFO))),
|
||||
ModifyList::new_purge_and_set(
|
||||
"domain_ldap_basedn",
|
||||
Value::new_iutf8("o=kanidmproject"),
|
||||
),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
|
|
@ -895,15 +895,12 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
.check_oauth2_account_uuid_valid(uuid, session_id, parent_session_id, iat, ct)
|
||||
.map_err(|_| admin_error!("Account is not valid"));
|
||||
|
||||
let entry = match valid {
|
||||
Ok(Some(entry)) => entry,
|
||||
_ => {
|
||||
security_info!(
|
||||
?uuid,
|
||||
"access token has no account not valid, returning inactive"
|
||||
);
|
||||
return Err(Oauth2Error::InvalidToken);
|
||||
}
|
||||
let Ok(Some(entry)) = valid else {
|
||||
security_info!(
|
||||
?uuid,
|
||||
"access token has no account not valid, returning inactive"
|
||||
);
|
||||
return Err(Oauth2Error::InvalidToken);
|
||||
};
|
||||
|
||||
// Check the not issued before of the session relative to this refresh iat
|
||||
|
@ -1612,15 +1609,12 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
|||
.check_oauth2_account_uuid_valid(uuid, session_id, parent_session_id, iat, ct)
|
||||
.map_err(|_| admin_error!("Account is not valid"));
|
||||
|
||||
let entry = match valid {
|
||||
Ok(Some(entry)) => entry,
|
||||
_ => {
|
||||
security_info!(
|
||||
?uuid,
|
||||
"access token has no account not valid, returning inactive"
|
||||
);
|
||||
return Ok(AccessTokenIntrospectResponse::inactive());
|
||||
}
|
||||
let Ok(Some(entry)) = valid else {
|
||||
security_info!(
|
||||
?uuid,
|
||||
"access token has no account not valid, returning inactive"
|
||||
);
|
||||
return Ok(AccessTokenIntrospectResponse::inactive());
|
||||
};
|
||||
|
||||
let account = match Account::try_from_entry_no_groups(&entry) {
|
||||
|
@ -1718,15 +1712,12 @@ impl<'a> IdmServerProxyReadTransaction<'a> {
|
|||
.check_oauth2_account_uuid_valid(uuid, session_id, parent_session_id, iat, ct)
|
||||
.map_err(|_| admin_error!("Account is not valid"));
|
||||
|
||||
let entry = match valid {
|
||||
Ok(Some(entry)) => entry,
|
||||
_ => {
|
||||
security_info!(
|
||||
?uuid,
|
||||
"access token has account not valid, returning inactive"
|
||||
);
|
||||
return Err(Oauth2Error::InvalidToken);
|
||||
}
|
||||
let Ok(Some(entry)) = valid else {
|
||||
security_info!(
|
||||
?uuid,
|
||||
"access token has account not valid, returning inactive"
|
||||
);
|
||||
return Err(Oauth2Error::InvalidToken);
|
||||
};
|
||||
|
||||
let account = match Account::try_from_entry_ro(&entry, &mut self.qs_read) {
|
||||
|
@ -2900,15 +2891,13 @@ mod tests {
|
|||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
// Expire the account, should cause introspect to return inactive.
|
||||
let v_expire = Value::new_datetime_epoch(Duration::from_secs(TEST_CURRENT_TIME - 1));
|
||||
let me_inv_m = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("account_expire"),
|
||||
v_expire,
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_inv_m = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("account_expire"),
|
||||
v_expire,
|
||||
)]),
|
||||
);
|
||||
// go!
|
||||
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
@ -3144,12 +3133,10 @@ mod tests {
|
|||
|
||||
// Delete the resource server.
|
||||
|
||||
let de = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"oauth2_rs_name",
|
||||
PartialValue::new_iname("test_resource_server")
|
||||
)))
|
||||
};
|
||||
let de = DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"oauth2_rs_name",
|
||||
PartialValue::new_iname("test_resource_server")
|
||||
)));
|
||||
|
||||
assert!(idms_prox_write.qs_write.delete(&de).is_ok());
|
||||
|
||||
|
@ -3962,22 +3949,20 @@ mod tests {
|
|||
// Great! Now change the scopes on the oauth2 instance, this revokes the permit.
|
||||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let me_extend_scopes = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq(
|
||||
"oauth2_rs_name",
|
||||
PartialValue::new_iname("test_resource_server")
|
||||
)),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("oauth2_rs_scope_map"),
|
||||
Value::new_oauthscopemap(
|
||||
UUID_IDM_ALL_ACCOUNTS,
|
||||
btreeset!["email".to_string(), "openid".to_string()],
|
||||
)
|
||||
.expect("invalid oauthscope"),
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_extend_scopes = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq(
|
||||
"oauth2_rs_name",
|
||||
PartialValue::new_iname("test_resource_server")
|
||||
)),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("oauth2_rs_scope_map"),
|
||||
Value::new_oauthscopemap(
|
||||
UUID_IDM_ALL_ACCOUNTS,
|
||||
btreeset!["email".to_string(), "openid".to_string()],
|
||||
)
|
||||
.expect("invalid oauthscope"),
|
||||
)]),
|
||||
);
|
||||
|
||||
assert!(idms_prox_write.qs_write.modify(&me_extend_scopes).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
@ -4027,22 +4012,17 @@ mod tests {
|
|||
// Now change the supplemental scopes on the oauth2 instance, this revokes the permit.
|
||||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
|
||||
let me_extend_scopes = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq(
|
||||
"oauth2_rs_name",
|
||||
PartialValue::new_iname("test_resource_server")
|
||||
)),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("oauth2_rs_sup_scope_map"),
|
||||
Value::new_oauthscopemap(
|
||||
UUID_IDM_ALL_ACCOUNTS,
|
||||
btreeset!["newscope".to_string()],
|
||||
)
|
||||
let me_extend_scopes = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq(
|
||||
"oauth2_rs_name",
|
||||
PartialValue::new_iname("test_resource_server")
|
||||
)),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("oauth2_rs_sup_scope_map"),
|
||||
Value::new_oauthscopemap(UUID_IDM_ALL_ACCOUNTS, btreeset!["newscope".to_string()])
|
||||
.expect("invalid oauthscope"),
|
||||
)]),
|
||||
)
|
||||
};
|
||||
)]),
|
||||
);
|
||||
|
||||
assert!(idms_prox_write.qs_write.modify(&me_extend_scopes).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
@ -4143,12 +4123,10 @@ mod tests {
|
|||
);
|
||||
|
||||
// Now trigger the delete of the RS
|
||||
let de = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"oauth2_rs_name",
|
||||
PartialValue::new_iname("test_resource_server")
|
||||
)))
|
||||
};
|
||||
let de = DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"oauth2_rs_name",
|
||||
PartialValue::new_iname("test_resource_server")
|
||||
)));
|
||||
|
||||
assert!(idms_prox_write.qs_write.delete(&de).is_ok());
|
||||
// Assert the consent maps are gone.
|
||||
|
|
|
@ -27,12 +27,9 @@ impl<'a> IdmServerAuthTransaction<'a> {
|
|||
) -> Result<AuthResult, OperationError> {
|
||||
// re-auth only works on users, so lets get the user account.
|
||||
// hint - it's in the ident!
|
||||
let entry = match ident.get_user_entry() {
|
||||
Some(entry) => entry,
|
||||
None => {
|
||||
error!("Ident is not a user and has no entry associated. Unable to proceed.");
|
||||
return Err(OperationError::InvalidState);
|
||||
}
|
||||
let Some(entry) = ident.get_user_entry() else {
|
||||
error!("Ident is not a user and has no entry associated. Unable to proceed.");
|
||||
return Err(OperationError::InvalidState);
|
||||
};
|
||||
|
||||
// Setup the account record.
|
||||
|
|
|
@ -1604,12 +1604,10 @@ mod tests {
|
|||
// -- Revoke the session
|
||||
|
||||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
let me_inv_m = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("test_scim_sync"))),
|
||||
ModifyList::new_list(vec![Modify::Purged(AttrString::from("sync_token_session"))]),
|
||||
)
|
||||
};
|
||||
let me_inv_m = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("test_scim_sync"))),
|
||||
ModifyList::new_list(vec![Modify::Purged(AttrString::from("sync_token_session"))]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
||||
|
@ -1628,14 +1626,12 @@ mod tests {
|
|||
.scim_sync_generate_token(>e, ct)
|
||||
.expect("failed to generate new scim sync token");
|
||||
|
||||
let me_inv_m = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("test_scim_sync"))),
|
||||
ModifyList::new_list(vec![Modify::Purged(AttrString::from(
|
||||
"jws_es256_private_key",
|
||||
))]),
|
||||
)
|
||||
};
|
||||
let me_inv_m = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("test_scim_sync"))),
|
||||
ModifyList::new_list(vec![Modify::Purged(AttrString::from(
|
||||
"jws_es256_private_key",
|
||||
))]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
||||
|
|
|
@ -1629,15 +1629,14 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
e
|
||||
})?;
|
||||
|
||||
let mp = unsafe {
|
||||
self.qs_write
|
||||
.modify_pre_apply(&me)
|
||||
.and_then(|opt_mp| opt_mp.ok_or(OperationError::NoMatchingEntries))
|
||||
.map_err(|e| {
|
||||
request_error!(error = ?e);
|
||||
e
|
||||
})?
|
||||
};
|
||||
let mp = self
|
||||
.qs_write
|
||||
.modify_pre_apply(&me)
|
||||
.and_then(|opt_mp| opt_mp.ok_or(OperationError::NoMatchingEntries))
|
||||
.map_err(|e| {
|
||||
request_error!(error = ?e);
|
||||
e
|
||||
})?;
|
||||
|
||||
// If we got here, then pre-apply succeeded, and that means access control
|
||||
// passed. Now we can do the extra checks.
|
||||
|
@ -1708,15 +1707,14 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
|||
e
|
||||
})?;
|
||||
|
||||
let mp = unsafe {
|
||||
self.qs_write
|
||||
.modify_pre_apply(&me)
|
||||
.and_then(|opt_mp| opt_mp.ok_or(OperationError::NoMatchingEntries))
|
||||
.map_err(|e| {
|
||||
request_error!(error = ?e);
|
||||
e
|
||||
})?
|
||||
};
|
||||
let mp = self
|
||||
.qs_write
|
||||
.modify_pre_apply(&me)
|
||||
.and_then(|opt_mp| opt_mp.ok_or(OperationError::NoMatchingEntries))
|
||||
.map_err(|e| {
|
||||
request_error!(error = ?e);
|
||||
e
|
||||
})?;
|
||||
|
||||
// If we got here, then pre-apply succeeded, and that means access control
|
||||
// passed. Now we can do the extra checks.
|
||||
|
@ -2249,15 +2247,13 @@ mod tests {
|
|||
let mut idms_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
|
||||
// now modify and provide a primary credential.
|
||||
let me_inv_m = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("primary_credential"),
|
||||
v_cred,
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_inv_m = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("primary_credential"),
|
||||
v_cred,
|
||||
)]),
|
||||
);
|
||||
// go!
|
||||
assert!(idms_write.qs_write.modify(&me_inv_m).is_ok());
|
||||
|
||||
|
@ -2542,7 +2538,12 @@ mod tests {
|
|||
idms_prox_write.commit().expect("failed to commit");
|
||||
|
||||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
let rate = RadiusAuthTokenEvent::new_internal(UUID_ADMIN);
|
||||
let admin_entry = idms_prox_read
|
||||
.qs_read
|
||||
.internal_search_uuid(UUID_ADMIN)
|
||||
.expect("Can't access admin entry.");
|
||||
|
||||
let rate = RadiusAuthTokenEvent::new_impersonate(admin_entry, UUID_ADMIN);
|
||||
let tok_r = idms_prox_read
|
||||
.get_radiusauthtoken(&rate, duration_from_epoch_now())
|
||||
.expect("Failed to generate radius auth token");
|
||||
|
@ -2603,15 +2604,13 @@ mod tests {
|
|||
async fn test_idm_unixusertoken(idms: &IdmServer, _idms_delayed: &IdmServerDelayed) {
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
// Modify admin to have posixaccount
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_posix = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||
// Add a posix group that has the admin as a member.
|
||||
let e: Entry<EntryInit, EntryNew> = entry_init!(
|
||||
|
@ -2638,7 +2637,16 @@ mod tests {
|
|||
|
||||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
|
||||
let ugte = UnixGroupTokenEvent::new_internal(uuid!("01609135-a1c4-43d5-966b-a28227644445"));
|
||||
// Get the account that will be doing the actual reads.
|
||||
let admin_entry = idms_prox_read
|
||||
.qs_read
|
||||
.internal_search_uuid(UUID_ADMIN)
|
||||
.expect("Can't access admin entry.");
|
||||
|
||||
let ugte = UnixGroupTokenEvent::new_impersonate(
|
||||
admin_entry.clone(),
|
||||
uuid!("01609135-a1c4-43d5-966b-a28227644445"),
|
||||
);
|
||||
let tok_g = idms_prox_read
|
||||
.get_unixgrouptoken(&ugte)
|
||||
.expect("Failed to generate unix group token");
|
||||
|
@ -2659,7 +2667,10 @@ mod tests {
|
|||
assert!(tok_r.valid);
|
||||
|
||||
// Show we can get the admin as a unix group token too
|
||||
let ugte = UnixGroupTokenEvent::new_internal(uuid!("00000000-0000-0000-0000-000000000000"));
|
||||
let ugte = UnixGroupTokenEvent::new_impersonate(
|
||||
admin_entry,
|
||||
uuid!("00000000-0000-0000-0000-000000000000"),
|
||||
);
|
||||
let tok_g = idms_prox_read
|
||||
.get_unixgrouptoken(&ugte)
|
||||
.expect("Failed to generate unix group token");
|
||||
|
@ -2675,15 +2686,13 @@ mod tests {
|
|||
) {
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
// make the admin a valid posix account
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_posix = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||
|
||||
let pce = UnixPasswordChangeEvent::new_internal(UUID_ADMIN, TEST_PASSWORD);
|
||||
|
@ -2715,12 +2724,10 @@ mod tests {
|
|||
|
||||
// Check deleting the password
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
let me_purge_up = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![Modify::Purged(AttrString::from("unix_password"))]),
|
||||
)
|
||||
};
|
||||
let me_purge_up = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![Modify::Purged(AttrString::from("unix_password"))]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_purge_up).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
||||
|
@ -2748,15 +2755,14 @@ mod tests {
|
|||
{
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
// now modify and provide a primary credential.
|
||||
let me_inv_m = unsafe {
|
||||
let me_inv_m =
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("password_import"),
|
||||
Value::from("{SSHA512}JwrSUHkI7FTAfHRVR6KoFlSN0E3dmaQWARjZ+/UsShYlENOqDtFVU77HJLLrY2MuSp0jve52+pwtdVl2QUAHukQ0XUf5LDtM")
|
||||
)]),
|
||||
)
|
||||
};
|
||||
);
|
||||
// go!
|
||||
assert!(idms_prox_write.qs_write.modify(&me_inv_m).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
|
@ -2830,16 +2836,14 @@ mod tests {
|
|||
let cred = Credential::new_from_password(pw);
|
||||
let v_cred = Value::new_credential("unix", cred);
|
||||
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
Modify::Present(AttrString::from("unix_password"), v_cred),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_posix = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
Modify::Present(AttrString::from("unix_password"), v_cred),
|
||||
]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
idms_delayed.check_is_empty_or_panic();
|
||||
|
@ -2887,15 +2891,13 @@ mod tests {
|
|||
let v_expire = Value::new_datetime_epoch(Duration::from_secs(TEST_EXPIRE_TIME));
|
||||
|
||||
// now modify and provide a primary credential.
|
||||
let me_inv_m = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("account_expire"), v_expire),
|
||||
Modify::Present(AttrString::from("account_valid_from"), v_valid_from),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_inv_m = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("account_expire"), v_expire),
|
||||
Modify::Present(AttrString::from("account_valid_from"), v_valid_from),
|
||||
]),
|
||||
);
|
||||
// go!
|
||||
assert!(idms_write.qs_write.modify(&me_inv_m).is_ok());
|
||||
|
||||
|
@ -2979,15 +2981,13 @@ mod tests {
|
|||
|
||||
// make the admin a valid posix account
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_posix = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||
|
||||
let pce = UnixPasswordChangeEvent::new_internal(UUID_ADMIN, TEST_PASSWORD);
|
||||
|
@ -3056,7 +3056,12 @@ mod tests {
|
|||
idms_prox_write.commit().expect("failed to commit");
|
||||
|
||||
let mut idms_prox_read = idms.proxy_read().await;
|
||||
let rate = RadiusAuthTokenEvent::new_internal(UUID_ADMIN);
|
||||
let admin_entry = idms_prox_read
|
||||
.qs_read
|
||||
.internal_search_uuid(UUID_ADMIN)
|
||||
.expect("Can't access admin entry.");
|
||||
|
||||
let rate = RadiusAuthTokenEvent::new_impersonate(admin_entry, UUID_ADMIN);
|
||||
let tok_r = idms_prox_read.get_radiusauthtoken(&rate, time_low);
|
||||
|
||||
if tok_r.is_err() {
|
||||
|
@ -3339,15 +3344,13 @@ mod tests {
|
|||
.expect("Failed to setup admin account");
|
||||
// make the admin a valid posix account
|
||||
let mut idms_prox_write = idms.proxy_write(duration_from_epoch_now()).await;
|
||||
let me_posix = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_posix = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("admin"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("posixaccount")),
|
||||
Modify::Present(AttrString::from("gidnumber"), Value::new_uint32(2001)),
|
||||
]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_posix).is_ok());
|
||||
|
||||
let pce = UnixPasswordChangeEvent::new_internal(UUID_ADMIN, TEST_PASSWORD);
|
||||
|
@ -3718,16 +3721,14 @@ mod tests {
|
|||
// fernet_private_key_str
|
||||
// es256_private_key_der
|
||||
let mut idms_prox_write = idms.proxy_write(ct).await;
|
||||
let me_reset_tokens = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("uuid", PartialValue::Uuid(UUID_DOMAIN_INFO))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Purged(AttrString::from("fernet_private_key_str")),
|
||||
Modify::Purged(AttrString::from("es256_private_key_der")),
|
||||
Modify::Purged(AttrString::from("domain_token_key")),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_reset_tokens = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("uuid", PartialValue::Uuid(UUID_DOMAIN_INFO))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Purged(AttrString::from("fernet_private_key_str")),
|
||||
Modify::Purged(AttrString::from("es256_private_key_der")),
|
||||
Modify::Purged(AttrString::from("domain_token_key")),
|
||||
]),
|
||||
);
|
||||
assert!(idms_prox_write.qs_write.modify(&me_reset_tokens).is_ok());
|
||||
assert!(idms_prox_write.commit().is_ok());
|
||||
// Check the old token is invalid, due to reload.
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
#![deny(warnings)]
|
||||
#![recursion_limit = "512"]
|
||||
#![warn(unused_extern_crates)]
|
||||
// Enable some groups of clippy lints.
|
||||
#![deny(clippy::suspicious)]
|
||||
#![deny(clippy::perf)]
|
||||
// Specific lints to enforce.
|
||||
// TODO: can't use this until we have a better way to handle the 'todo' lint?
|
||||
// #![deny(clippy::todo)]
|
||||
#![warn(clippy::todo)]
|
||||
|
@ -15,6 +19,7 @@
|
|||
#![deny(clippy::needless_pass_by_value)]
|
||||
#![deny(clippy::trivially_copy_pass_by_ref)]
|
||||
#![deny(clippy::disallowed_types)]
|
||||
#![deny(clippy::manual_let_else)]
|
||||
#![allow(clippy::unreachable)]
|
||||
|
||||
#[cfg(all(jemallocator, test, not(target_family = "windows")))]
|
||||
|
|
|
@ -69,7 +69,7 @@ macro_rules! entry_to_account {
|
|||
use crate::idm::account::Account;
|
||||
use crate::value::Value;
|
||||
|
||||
let mut e: Entry<EntryInvalid, EntryNew> = unsafe { $entry.clone().into_invalid_new() };
|
||||
let mut e: Entry<EntryInvalid, EntryNew> = $entry.clone().into_invalid_new();
|
||||
// Add spn, because normally this is generated but in tests we can't.
|
||||
let spn = e
|
||||
.get_ava_single_iname("name")
|
||||
|
@ -77,7 +77,7 @@ macro_rules! entry_to_account {
|
|||
.expect("Failed to munge spn from name!");
|
||||
e.set_ava("spn", once(spn));
|
||||
|
||||
let e = unsafe { e.into_sealed_committed() };
|
||||
let e = e.into_sealed_committed();
|
||||
|
||||
Account::try_from_entry_no_groups(&e).expect("Account conversion failure")
|
||||
}};
|
||||
|
@ -171,10 +171,8 @@ macro_rules! run_modify_test {
|
|||
}
|
||||
|
||||
let me = match $internal {
|
||||
None => unsafe { ModifyEvent::new_internal_invalid($modify_filter, $modify_list) },
|
||||
Some(ent) => unsafe {
|
||||
ModifyEvent::new_impersonate_entry(ent, $modify_filter, $modify_list)
|
||||
},
|
||||
None => ModifyEvent::new_internal_invalid($modify_filter, $modify_list),
|
||||
Some(ent) => ModifyEvent::new_impersonate_entry(ent, $modify_filter, $modify_list),
|
||||
};
|
||||
|
||||
{
|
||||
|
@ -227,8 +225,8 @@ macro_rules! run_delete_test {
|
|||
let qs = setup_test!($preload_entries);
|
||||
|
||||
let de = match $internal {
|
||||
Some(ent) => unsafe { DeleteEvent::new_impersonate_entry(ent, $delete_filter.clone()) },
|
||||
None => unsafe { DeleteEvent::new_internal_invalid($delete_filter.clone()) },
|
||||
Some(ent) => DeleteEvent::new_impersonate_entry(ent, $delete_filter.clone()),
|
||||
None => DeleteEvent::new_internal_invalid($delete_filter.clone()),
|
||||
};
|
||||
|
||||
{
|
||||
|
|
|
@ -227,8 +227,10 @@ impl ModifyList<ModifyInvalid> {
|
|||
})
|
||||
}
|
||||
|
||||
/// ⚠️ - Convert a modlist to be considered valid, bypassing schema.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub(crate) unsafe fn into_valid(self) -> ModifyList<ModifyValid> {
|
||||
pub(crate) fn into_valid(self) -> ModifyList<ModifyValid> {
|
||||
ModifyList {
|
||||
valid: ModifyValid,
|
||||
mods: self.mods,
|
||||
|
@ -237,8 +239,10 @@ impl ModifyList<ModifyInvalid> {
|
|||
}
|
||||
|
||||
impl ModifyList<ModifyValid> {
|
||||
/// ⚠️ - Create a new modlist that is considered valid, bypassing schema.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_valid_list(mods: Vec<Modify>) -> Self {
|
||||
pub fn new_valid_list(mods: Vec<Modify>) -> Self {
|
||||
ModifyList {
|
||||
valid: ModifyValid,
|
||||
mods,
|
||||
|
|
|
@ -302,7 +302,7 @@ mod tests {
|
|||
pub static ref PRELOAD: Vec<EntryInitNew> =
|
||||
vec![TEST_ACCOUNT.clone(), TEST_GROUP.clone(), ALLOW_ALL.clone()];
|
||||
pub static ref E_TEST_ACCOUNT: Arc<EntrySealedCommitted> =
|
||||
Arc::new(unsafe { TEST_ACCOUNT.clone().into_sealed_committed() });
|
||||
Arc::new(TEST_ACCOUNT.clone().into_sealed_committed());
|
||||
}
|
||||
|
||||
// check create where no uuid
|
||||
|
|
|
@ -169,10 +169,10 @@ mod tests {
|
|||
.get_ava_set("name_history")
|
||||
.expect("failed to get primary cred.");
|
||||
dbg!(c.clone());
|
||||
return assert!(
|
||||
assert!(
|
||||
c.contains(&PartialValue::new_utf8s("old_name"))
|
||||
&& c.contains(&PartialValue::new_utf8s("new_name_1"))
|
||||
);
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -207,7 +207,7 @@ mod tests {
|
|||
.get_ava_set("name_history")
|
||||
.expect("failed to get name_history ava");
|
||||
|
||||
return assert!(name_history.contains(&PartialValue::new_utf8s(&"old_name")));
|
||||
assert!(name_history.contains(&PartialValue::new_utf8s("old_name")))
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -257,10 +257,10 @@ mod tests {
|
|||
let c = e
|
||||
.get_ava_set("name_history")
|
||||
.expect("failed to get name_history ava :/");
|
||||
return assert!(
|
||||
!c.contains(&PartialValue::new_utf8s(&"old_name1"))
|
||||
&& c.contains(&PartialValue::new_utf8s(&"new_name"))
|
||||
);
|
||||
assert!(
|
||||
!c.contains(&PartialValue::new_utf8s("old_name1"))
|
||||
&& c.contains(&PartialValue::new_utf8s("new_name"))
|
||||
)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -371,7 +371,7 @@ mod tests {
|
|||
pub static ref PRELOAD: Vec<EntryInitNew> =
|
||||
vec![TEST_ACCOUNT.clone(), TEST_GROUP.clone(), ALLOW_ALL.clone()];
|
||||
pub static ref E_TEST_ACCOUNT: Arc<EntrySealedCommitted> =
|
||||
Arc::new(unsafe { TEST_ACCOUNT.clone().into_sealed_committed() });
|
||||
Arc::new(TEST_ACCOUNT.clone().into_sealed_committed());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -605,12 +605,11 @@ mod tests {
|
|||
None,
|
||||
|qs: &mut QueryServerWriteTransaction| {
|
||||
// Any pre_hooks we need. In this case, we need to trigger the delete of testgroup_a
|
||||
let de_sin = unsafe {
|
||||
let de_sin =
|
||||
crate::event::DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testgroup_a")
|
||||
)])))
|
||||
};
|
||||
)])));
|
||||
assert!(qs.delete(&de_sin).is_ok());
|
||||
},
|
||||
|_| {}
|
||||
|
|
|
@ -98,17 +98,14 @@ impl Plugin for Spn {
|
|||
let mut r = Vec::new();
|
||||
|
||||
for e in all_cand {
|
||||
let g_spn = match e.generate_spn(&domain_name) {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
admin_error!(
|
||||
uuid = ?e.get_uuid(),
|
||||
"Entry SPN could not be generated (missing name!?)",
|
||||
);
|
||||
debug_assert!(false);
|
||||
r.push(Err(ConsistencyError::InvalidSpn(e.get_id())));
|
||||
continue;
|
||||
}
|
||||
let Some(g_spn) = e.generate_spn(&domain_name) else {
|
||||
admin_error!(
|
||||
uuid = ?e.get_uuid(),
|
||||
"Entry SPN could not be generated (missing name!?)",
|
||||
);
|
||||
debug_assert!(false);
|
||||
r.push(Err(ConsistencyError::InvalidSpn(e.get_id())));
|
||||
continue;
|
||||
};
|
||||
match e.get_ava_single("spn") {
|
||||
Some(r_spn) => {
|
||||
|
@ -182,9 +179,8 @@ impl Spn {
|
|||
}
|
||||
});
|
||||
|
||||
let domain_name = match domain_name_changed {
|
||||
Some(s) => s,
|
||||
None => return Ok(()),
|
||||
let Some(domain_name) = domain_name_changed else {
|
||||
return Ok(())
|
||||
};
|
||||
|
||||
admin_info!(
|
||||
|
@ -337,11 +333,9 @@ mod tests {
|
|||
// trigger the domain_name change (this will be a cli option to the server
|
||||
// in the final version), but it will still call the same qs function to perform the
|
||||
// change.
|
||||
unsafe {
|
||||
server_txn
|
||||
.domain_rename_inner("new.example.com")
|
||||
.expect("should not fail!");
|
||||
}
|
||||
server_txn
|
||||
.danger_domain_rename("new.example.com")
|
||||
.expect("should not fail!");
|
||||
|
||||
// check the spn on admin is admin@<new domain>
|
||||
let e_post = server_txn
|
||||
|
|
|
@ -33,27 +33,23 @@ impl Cid {
|
|||
Cid { ts, s_uuid }
|
||||
}
|
||||
|
||||
/// ⚠️ - Create a new cid at timestamp zero.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_zero() -> Self {
|
||||
pub fn new_zero() -> Self {
|
||||
Self::new_count(0)
|
||||
}
|
||||
|
||||
/// ⚠️ - Create a new cid with a manually defined timestamp.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub unsafe fn new_count(c: u64) -> Self {
|
||||
pub fn new_count(c: u64) -> Self {
|
||||
Cid {
|
||||
s_uuid: uuid!("00000000-0000-0000-0000-000000000000"),
|
||||
ts: Duration::new(c, 0),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn new_random_s_d(ts: Duration) -> Self {
|
||||
Cid {
|
||||
s_uuid: Uuid::new_v4(),
|
||||
ts,
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::expect_used)]
|
||||
pub fn sub_secs(&self, secs: u64) -> Result<Self, OperationError> {
|
||||
self.ts
|
||||
|
@ -113,7 +109,7 @@ mod tests {
|
|||
let ts10 = Duration::new(10, 0);
|
||||
let ts15 = Duration::new(15, 0);
|
||||
|
||||
let cid_z = unsafe { Cid::new_zero() };
|
||||
let cid_z = Cid::new_zero();
|
||||
|
||||
let cid_a = Cid::new_lamport(s_uuid, ts5, &ts5);
|
||||
assert!(cid_a.cmp(&cid_z) == Ordering::Greater);
|
||||
|
|
|
@ -234,16 +234,13 @@ pub trait ReplicationUpdateVectorTransaction {
|
|||
// For each server and range low to high, iterate over
|
||||
// the list of CID's in the main RUV.
|
||||
|
||||
let ruv_range = match range.get(s_uuid) {
|
||||
Some(r) => r,
|
||||
None => {
|
||||
// This is valid because if we clean up a server range on
|
||||
// this node, but the other server isn't aware yet, so we
|
||||
// just no-op this. The changes we have will still be
|
||||
// correctly found and sent.
|
||||
debug!(?s_uuid, "range not found in ruv.");
|
||||
continue;
|
||||
}
|
||||
let Some(ruv_range) = range.get(s_uuid) else {
|
||||
// This is valid because if we clean up a server range on
|
||||
// this node, but the other server isn't aware yet, so we
|
||||
// just no-op this. The changes we have will still be
|
||||
// correctly found and sent.
|
||||
debug!(?s_uuid, "range not found in ruv.");
|
||||
continue;
|
||||
};
|
||||
|
||||
// Get from the min to the max. Unbounded and
|
||||
|
|
|
@ -2002,7 +2002,7 @@ mod tests {
|
|||
$type:ty
|
||||
) => {{
|
||||
let e1: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str($e);
|
||||
let ev1 = unsafe { e1.into_sealed_committed() };
|
||||
let ev1 = e1.into_sealed_committed();
|
||||
|
||||
let r1 = <$type>::try_from(&ev1);
|
||||
assert!(r1.is_ok());
|
||||
|
@ -2015,7 +2015,7 @@ mod tests {
|
|||
$type:ty
|
||||
) => {{
|
||||
let e1: Entry<EntryInit, EntryNew> = Entry::unsafe_from_entry_str($e);
|
||||
let ev1 = unsafe { e1.into_sealed_committed() };
|
||||
let ev1 = e1.into_sealed_committed();
|
||||
|
||||
let r1 = <$type>::try_from(&ev1);
|
||||
assert!(r1.is_err());
|
||||
|
@ -2363,94 +2363,84 @@ mod tests {
|
|||
let schema_outer = Schema::new().expect("failed to create schema");
|
||||
let schema = schema_outer.read();
|
||||
|
||||
let e_no_uuid = unsafe { entry_init!().into_invalid_new() };
|
||||
let e_no_uuid = entry_init!().into_invalid_new();
|
||||
|
||||
assert_eq!(
|
||||
e_no_uuid.validate(&schema),
|
||||
Err(SchemaError::MissingMustAttribute(vec!["uuid".to_string()]))
|
||||
);
|
||||
|
||||
let e_no_class = unsafe {
|
||||
entry_init!((
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
))
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_no_class = entry_init!((
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
))
|
||||
.into_invalid_new();
|
||||
|
||||
assert_eq!(e_no_class.validate(&schema), Err(SchemaError::NoClassFound));
|
||||
|
||||
let e_bad_class = unsafe {
|
||||
entry_init!(
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("class", Value::new_class("zzzzzz"))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_bad_class = entry_init!(
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("class", Value::new_class("zzzzzz"))
|
||||
)
|
||||
.into_invalid_new();
|
||||
assert_eq!(
|
||||
e_bad_class.validate(&schema),
|
||||
Err(SchemaError::InvalidClass(vec!["zzzzzz".to_string()]))
|
||||
);
|
||||
|
||||
let e_attr_invalid = unsafe {
|
||||
entry_init!(
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone())
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_attr_invalid = entry_init!(
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone())
|
||||
)
|
||||
.into_invalid_new();
|
||||
let res = e_attr_invalid.validate(&schema);
|
||||
assert!(match res {
|
||||
Err(SchemaError::MissingMustAttribute(_)) => true,
|
||||
_ => false,
|
||||
});
|
||||
|
||||
let e_attr_invalid_may = unsafe {
|
||||
entry_init!(
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone()),
|
||||
("attributename", Value::new_iutf8("testattr")),
|
||||
("description", Value::Utf8("testattr".to_string())),
|
||||
("multivalue", Value::Bool(false)),
|
||||
("unique", Value::Bool(false)),
|
||||
("syntax", Value::Syntax(SyntaxType::Utf8String)),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("zzzzz", Value::Utf8("zzzz".to_string()))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_attr_invalid_may = entry_init!(
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone()),
|
||||
("attributename", Value::new_iutf8("testattr")),
|
||||
("description", Value::Utf8("testattr".to_string())),
|
||||
("multivalue", Value::Bool(false)),
|
||||
("unique", Value::Bool(false)),
|
||||
("syntax", Value::Syntax(SyntaxType::Utf8String)),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("zzzzz", Value::Utf8("zzzz".to_string()))
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
assert_eq!(
|
||||
e_attr_invalid_may.validate(&schema),
|
||||
Err(SchemaError::AttributeNotValidForClass("zzzzz".to_string()))
|
||||
);
|
||||
|
||||
let e_attr_invalid_syn = unsafe {
|
||||
entry_init!(
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone()),
|
||||
("attributename", Value::new_iutf8("testattr")),
|
||||
("description", Value::Utf8("testattr".to_string())),
|
||||
("multivalue", Value::Utf8("false".to_string())),
|
||||
("unique", Value::Bool(false)),
|
||||
("syntax", Value::Syntax(SyntaxType::Utf8String)),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
)
|
||||
let e_attr_invalid_syn = entry_init!(
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone()),
|
||||
("attributename", Value::new_iutf8("testattr")),
|
||||
("description", Value::Utf8("testattr".to_string())),
|
||||
("multivalue", Value::Utf8("false".to_string())),
|
||||
("unique", Value::Bool(false)),
|
||||
("syntax", Value::Syntax(SyntaxType::Utf8String)),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
assert_eq!(
|
||||
e_attr_invalid_syn.validate(&schema),
|
||||
|
@ -2460,41 +2450,37 @@ mod tests {
|
|||
);
|
||||
|
||||
// You may not have the phantom.
|
||||
let e_phantom = unsafe {
|
||||
entry_init!(
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone()),
|
||||
("attributename", Value::new_iutf8("testattr")),
|
||||
("description", Value::Utf8("testattr".to_string())),
|
||||
("multivalue", Value::Bool(false)),
|
||||
("unique", Value::Bool(false)),
|
||||
("syntax", Value::Syntax(SyntaxType::Utf8String)),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("password_import", Value::Utf8("password".to_string()))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_phantom = entry_init!(
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone()),
|
||||
("attributename", Value::new_iutf8("testattr")),
|
||||
("description", Value::Utf8("testattr".to_string())),
|
||||
("multivalue", Value::Bool(false)),
|
||||
("unique", Value::Bool(false)),
|
||||
("syntax", Value::Syntax(SyntaxType::Utf8String)),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
),
|
||||
("password_import", Value::Utf8("password".to_string()))
|
||||
)
|
||||
.into_invalid_new();
|
||||
assert!(e_phantom.validate(&schema).is_err());
|
||||
|
||||
let e_ok = unsafe {
|
||||
entry_init!(
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone()),
|
||||
("attributename", Value::new_iutf8("testattr")),
|
||||
("description", Value::Utf8("testattr".to_string())),
|
||||
("multivalue", Value::Bool(true)),
|
||||
("unique", Value::Bool(false)),
|
||||
("syntax", Value::Syntax(SyntaxType::Utf8String)),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
)
|
||||
let e_ok = entry_init!(
|
||||
("class", CLASS_OBJECT.clone()),
|
||||
("class", CLASS_ATTRIBUTETYPE.clone()),
|
||||
("attributename", Value::new_iutf8("testattr")),
|
||||
("description", Value::Utf8("testattr".to_string())),
|
||||
("multivalue", Value::Bool(true)),
|
||||
("unique", Value::Bool(false)),
|
||||
("syntax", Value::Syntax(SyntaxType::Utf8String)),
|
||||
(
|
||||
"uuid",
|
||||
Value::Uuid(uuid::uuid!("db237e8a-0079-4b8c-8a56-593b22aa44d1"))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
)
|
||||
.into_invalid_new();
|
||||
assert!(e_ok.validate(&schema).is_ok());
|
||||
}
|
||||
|
||||
|
@ -2508,9 +2494,8 @@ mod tests {
|
|||
// check index to upper
|
||||
// insense to lower
|
||||
// attr name to lower
|
||||
let e_test: Entry<EntryInvalid, EntryNew> = unsafe {
|
||||
Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
let e_test: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["extensibleobject"],
|
||||
"name": ["TestPerson"],
|
||||
|
@ -2519,13 +2504,11 @@ mod tests {
|
|||
"InDeX": ["equality"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
let e_expect: Entry<EntryValid, EntryNew> = unsafe {
|
||||
Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
let e_expect: Entry<EntryValid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["extensibleobject"],
|
||||
"name": ["testperson"],
|
||||
|
@ -2534,9 +2517,8 @@ mod tests {
|
|||
"index": ["EQUALITY"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.into_valid_new()
|
||||
};
|
||||
)
|
||||
.into_valid_new();
|
||||
|
||||
let e_valid = e_test.validate(&schema).expect("validation failure");
|
||||
|
||||
|
@ -2549,18 +2531,16 @@ mod tests {
|
|||
let schema = schema_outer.read();
|
||||
// Just because you are extensible, doesn't mean you can be lazy
|
||||
|
||||
let e_extensible_bad: Entry<EntryInvalid, EntryNew> = unsafe {
|
||||
Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
let e_extensible_bad: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["extensibleobject"],
|
||||
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||
"multivalue": ["zzzz"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
assert_eq!(
|
||||
e_extensible_bad.validate(&schema),
|
||||
|
@ -2570,36 +2550,32 @@ mod tests {
|
|||
);
|
||||
|
||||
// Extensible doesn't mean you can have the phantoms
|
||||
let e_extensible_phantom: Entry<EntryInvalid, EntryNew> = unsafe {
|
||||
Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
let e_extensible_phantom: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["extensibleobject"],
|
||||
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||
"password_import": ["zzzz"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
assert_eq!(
|
||||
e_extensible_phantom.validate(&schema),
|
||||
Err(SchemaError::PhantomAttribute("password_import".to_string()))
|
||||
);
|
||||
|
||||
let e_extensible: Entry<EntryInvalid, EntryNew> = unsafe {
|
||||
Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
let e_extensible: Entry<EntryInvalid, EntryNew> = Entry::unsafe_from_entry_str(
|
||||
r#"{
|
||||
"attrs": {
|
||||
"class": ["extensibleobject"],
|
||||
"uuid": ["db237e8a-0079-4b8c-8a56-593b22aa44d1"],
|
||||
"multivalue": ["true"]
|
||||
}
|
||||
}"#,
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
/* Is okay because extensible! */
|
||||
assert!(e_extensible.validate(&schema).is_ok());
|
||||
|
@ -2628,7 +2604,10 @@ mod tests {
|
|||
let f_insense = filter_all!(f_eq("class", PartialValue::new_class("AttributeType")));
|
||||
assert_eq!(
|
||||
f_insense.validate(&schema),
|
||||
Ok(unsafe { filter_valid!(f_eq("class", PartialValue::new_class("attributetype"))) })
|
||||
Ok(filter_valid!(f_eq(
|
||||
"class",
|
||||
PartialValue::new_class("attributetype")
|
||||
)))
|
||||
);
|
||||
// Test the recursive structures validate
|
||||
let f_or_empty = filter_all!(f_or!([]));
|
||||
|
@ -2658,13 +2637,11 @@ mod tests {
|
|||
])));
|
||||
assert_eq!(
|
||||
f_or_ok.validate(&schema),
|
||||
Ok(unsafe {
|
||||
filter_valid!(f_andnot(f_and!([
|
||||
f_eq("class", PartialValue::new_class("attributetype")),
|
||||
f_sub("class", PartialValue::new_class("classtype")),
|
||||
f_pres("class")
|
||||
])))
|
||||
})
|
||||
Ok(filter_valid!(f_andnot(f_and!([
|
||||
f_eq("class", PartialValue::new_class("attributetype")),
|
||||
f_sub("class", PartialValue::new_class("classtype")),
|
||||
f_pres("class")
|
||||
]))))
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -2744,13 +2721,11 @@ mod tests {
|
|||
.is_ok());
|
||||
|
||||
// Missing person or service account.
|
||||
let e_account = unsafe {
|
||||
entry_init!(
|
||||
("class", Value::new_class("account")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_account = entry_init!(
|
||||
("class", Value::new_class("account")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
assert_eq!(
|
||||
e_account.validate(&schema),
|
||||
|
@ -2774,15 +2749,13 @@ mod tests {
|
|||
*/
|
||||
|
||||
// Service can't have person
|
||||
let e_service_person = unsafe {
|
||||
entry_init!(
|
||||
("class", Value::new_class("service")),
|
||||
("class", Value::new_class("account")),
|
||||
("class", Value::new_class("person")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_service_person = entry_init!(
|
||||
("class", Value::new_class("service")),
|
||||
("class", Value::new_class("account")),
|
||||
("class", Value::new_class("person")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
assert_eq!(
|
||||
e_service_person.validate(&schema),
|
||||
|
@ -2792,35 +2765,29 @@ mod tests {
|
|||
);
|
||||
|
||||
// These are valid configurations.
|
||||
let e_service_valid = unsafe {
|
||||
entry_init!(
|
||||
("class", Value::new_class("service")),
|
||||
("class", Value::new_class("account")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_service_valid = entry_init!(
|
||||
("class", Value::new_class("service")),
|
||||
("class", Value::new_class("account")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
assert!(e_service_valid.validate(&schema).is_ok());
|
||||
|
||||
let e_person_valid = unsafe {
|
||||
entry_init!(
|
||||
("class", Value::new_class("person")),
|
||||
("class", Value::new_class("account")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_person_valid = entry_init!(
|
||||
("class", Value::new_class("person")),
|
||||
("class", Value::new_class("account")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
assert!(e_person_valid.validate(&schema).is_ok());
|
||||
|
||||
let e_person_valid = unsafe {
|
||||
entry_init!(
|
||||
("class", Value::new_class("person")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new()
|
||||
};
|
||||
let e_person_valid = entry_init!(
|
||||
("class", Value::new_class("person")),
|
||||
("uuid", Value::Uuid(Uuid::new_v4()))
|
||||
)
|
||||
.into_invalid_new();
|
||||
|
||||
assert!(e_person_valid.validate(&schema).is_ok());
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,8 +41,10 @@ impl AccessControlSearch {
|
|||
Ok(AccessControlSearch { acp, attrs })
|
||||
}
|
||||
|
||||
/// ⚠️ - Manually create a search access profile from values.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub(super) unsafe fn from_raw(
|
||||
pub(super) fn from_raw(
|
||||
name: &str,
|
||||
uuid: Uuid,
|
||||
receiver: Uuid,
|
||||
|
@ -83,8 +85,10 @@ impl AccessControlDelete {
|
|||
})
|
||||
}
|
||||
|
||||
/// ⚠️ - Manually create a delete access profile from values.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub(super) unsafe fn from_raw(
|
||||
pub(super) fn from_raw(
|
||||
name: &str,
|
||||
uuid: Uuid,
|
||||
receiver: Uuid,
|
||||
|
@ -137,8 +141,10 @@ impl AccessControlCreate {
|
|||
})
|
||||
}
|
||||
|
||||
/// ⚠️ - Manually create a create access profile from values.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub(super) unsafe fn from_raw(
|
||||
pub(super) fn from_raw(
|
||||
name: &str,
|
||||
uuid: Uuid,
|
||||
receiver: Uuid,
|
||||
|
@ -202,8 +208,10 @@ impl AccessControlModify {
|
|||
})
|
||||
}
|
||||
|
||||
/// ⚠️ - Manually create a modify access profile from values.
|
||||
/// This is a TEST ONLY method and will never be exposed in production.
|
||||
#[cfg(test)]
|
||||
pub(super) unsafe fn from_raw(
|
||||
pub(super) fn from_raw(
|
||||
name: &str,
|
||||
uuid: Uuid,
|
||||
receiver: Uuid,
|
||||
|
|
|
@ -172,7 +172,7 @@ mod tests {
|
|||
let filt = filter!(f_eq("name", PartialValue::new_iname("testperson")));
|
||||
let admin = server_txn.internal_search_uuid(UUID_ADMIN).expect("failed");
|
||||
|
||||
let se1 = unsafe { SearchEvent::new_impersonate_entry(admin, filt) };
|
||||
let se1 = SearchEvent::new_impersonate_entry(admin, filt);
|
||||
|
||||
let mut e = entry_init!(
|
||||
("class", Value::new_class("object")),
|
||||
|
@ -212,7 +212,7 @@ mod tests {
|
|||
Value::AuditLogString(server_txn.get_txn_cid().clone(), "testperson".to_string()),
|
||||
);
|
||||
|
||||
let expected = unsafe { vec![Arc::new(e.into_sealed_committed())] };
|
||||
let expected = vec![Arc::new(e.into_sealed_committed())];
|
||||
|
||||
assert_eq!(r2, expected);
|
||||
|
||||
|
@ -230,12 +230,12 @@ mod tests {
|
|||
let admin = server_a_txn
|
||||
.internal_search_uuid(UUID_ADMIN)
|
||||
.expect("failed");
|
||||
let se_a = unsafe { SearchEvent::new_impersonate_entry(admin, filt.clone()) };
|
||||
let se_a = SearchEvent::new_impersonate_entry(admin, filt.clone());
|
||||
|
||||
let admin = server_b_txn
|
||||
.internal_search_uuid(UUID_ADMIN)
|
||||
.expect("failed");
|
||||
let se_b = unsafe { SearchEvent::new_impersonate_entry(admin, filt) };
|
||||
let se_b = SearchEvent::new_impersonate_entry(admin, filt);
|
||||
|
||||
let e = entry_init!(
|
||||
("class", Value::new_class("person")),
|
||||
|
|
|
@ -234,35 +234,28 @@ mod tests {
|
|||
assert!(cr.is_ok());
|
||||
|
||||
// Delete filter is syntax invalid
|
||||
let de_inv =
|
||||
unsafe { DeleteEvent::new_internal_invalid(filter!(f_pres("nhtoaunaoehtnu"))) };
|
||||
let de_inv = DeleteEvent::new_internal_invalid(filter!(f_pres("nhtoaunaoehtnu")));
|
||||
assert!(server_txn.delete(&de_inv).is_err());
|
||||
|
||||
// Delete deletes nothing
|
||||
let de_empty = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"uuid",
|
||||
PartialValue::Uuid(uuid!("cc8e95b4-c24f-4d68-ba54-000000000000"))
|
||||
)))
|
||||
};
|
||||
let de_empty = DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"uuid",
|
||||
PartialValue::Uuid(uuid!("cc8e95b4-c24f-4d68-ba54-000000000000"))
|
||||
)));
|
||||
assert!(server_txn.delete(&de_empty).is_err());
|
||||
|
||||
// Delete matches one
|
||||
let de_sin = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson3")
|
||||
)))
|
||||
};
|
||||
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson3")
|
||||
)));
|
||||
assert!(server_txn.delete(&de_sin).is_ok());
|
||||
|
||||
// Delete matches many
|
||||
let de_mult = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"description",
|
||||
PartialValue::new_utf8s("testperson")
|
||||
)))
|
||||
};
|
||||
let de_mult = DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"description",
|
||||
PartialValue::new_utf8s("testperson")
|
||||
)));
|
||||
assert!(server_txn.delete(&de_mult).is_ok());
|
||||
|
||||
assert!(server_txn.commit().is_ok());
|
||||
|
|
|
@ -153,9 +153,8 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
// correctly!
|
||||
trace!("internal_migrate_or_create operating on {:?}", e.get_uuid());
|
||||
|
||||
let filt = match e.filter_from_attrs(&[AttrString::from("uuid")]) {
|
||||
Some(f) => f,
|
||||
None => return Err(OperationError::FilterGeneration),
|
||||
let Some(filt) = e.filter_from_attrs(&[AttrString::from("uuid")]) else {
|
||||
return Err(OperationError::FilterGeneration)
|
||||
};
|
||||
|
||||
trace!("internal_migrate_or_create search {:?}", filt);
|
||||
|
|
|
@ -1479,13 +1479,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
|
||||
/// Initiate a domain rename process. This is generally an internal function but it's
|
||||
/// exposed to the cli for admins to be able to initiate the process.
|
||||
pub fn domain_rename(&mut self, new_domain_name: &str) -> Result<(), OperationError> {
|
||||
// We can't use the d_info struct here, because this has the database version of the domain
|
||||
// name, not the in memory (config) version. We need to accept the domain's
|
||||
// new name from the caller so we can change this.
|
||||
unsafe { self.domain_rename_inner(new_domain_name) }
|
||||
}
|
||||
|
||||
///
|
||||
/// # Safety
|
||||
/// This is UNSAFE because while it may change the domain name, it doesn't update
|
||||
/// the running configured version of the domain name that is resident to the
|
||||
|
@ -1495,10 +1489,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
/// that impacts spns, but in the future we may need to reconsider how this is
|
||||
/// approached, especially if we have a domain re-name replicated to us. It could
|
||||
/// be that we end up needing to have this as a cow cell or similar?
|
||||
pub(crate) unsafe fn domain_rename_inner(
|
||||
&mut self,
|
||||
new_domain_name: &str,
|
||||
) -> Result<(), OperationError> {
|
||||
pub fn danger_domain_rename(&mut self, new_domain_name: &str) -> Result<(), OperationError> {
|
||||
let modl = ModifyList::new_purge_and_set("domain_name", Value::new_iname(new_domain_name));
|
||||
let udi = PVUUID_DOMAIN_INFO.clone();
|
||||
let filt = filter_all!(f_eq("uuid", udi));
|
||||
|
@ -1830,12 +1821,10 @@ mod tests {
|
|||
// Start a new write
|
||||
let mut server_txn = server.write(duration_from_epoch_now()).await;
|
||||
// delete the class
|
||||
let de_class = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"classname",
|
||||
PartialValue::new_class("testclass")
|
||||
)))
|
||||
};
|
||||
let de_class = DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"classname",
|
||||
PartialValue::new_class("testclass")
|
||||
)));
|
||||
assert!(server_txn.delete(&de_class).is_ok());
|
||||
// Commit
|
||||
server_txn.commit().expect("should not fail");
|
||||
|
@ -1908,12 +1897,10 @@ mod tests {
|
|||
// Start a new write
|
||||
let mut server_txn = server.write(duration_from_epoch_now()).await;
|
||||
// delete the attr
|
||||
let de_attr = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"attributename",
|
||||
PartialValue::new_iutf8("testattr")
|
||||
)))
|
||||
};
|
||||
let de_attr = DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"attributename",
|
||||
PartialValue::new_iutf8("testattr")
|
||||
)));
|
||||
assert!(server_txn.delete(&de_attr).is_ok());
|
||||
// Commit
|
||||
server_txn.commit().expect("should not fail");
|
||||
|
|
|
@ -12,7 +12,7 @@ pub(crate) struct ModifyPartial<'a> {
|
|||
impl<'a> QueryServerWriteTransaction<'a> {
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn modify(&mut self, me: &ModifyEvent) -> Result<(), OperationError> {
|
||||
let mp = unsafe { self.modify_pre_apply(me)? };
|
||||
let mp = self.modify_pre_apply(me)?;
|
||||
if let Some(mp) = mp {
|
||||
self.modify_apply(mp)
|
||||
} else {
|
||||
|
@ -25,7 +25,7 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
/// the Ok(None) case which occurs during internal operations, and that you DO NOT re-order
|
||||
/// and call multiple pre-applies at the same time, else you can cause DB corruption.
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub(crate) unsafe fn modify_pre_apply<'x>(
|
||||
pub(crate) fn modify_pre_apply<'x>(
|
||||
&mut self,
|
||||
me: &'x ModifyEvent,
|
||||
) -> Result<Option<ModifyPartial<'x>>, OperationError> {
|
||||
|
@ -511,25 +511,21 @@ mod tests {
|
|||
assert!(cr.is_ok());
|
||||
|
||||
// Empty Modlist (filter is valid)
|
||||
let me_emp = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_pres("class")),
|
||||
ModifyList::new_list(vec![]),
|
||||
)
|
||||
};
|
||||
let me_emp = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_pres("class")),
|
||||
ModifyList::new_list(vec![]),
|
||||
);
|
||||
assert!(server_txn.modify(&me_emp) == Err(OperationError::EmptyRequest));
|
||||
|
||||
// Mod changes no objects
|
||||
let me_nochg = unsafe {
|
||||
ModifyEvent::new_impersonate_entry_ser(
|
||||
JSON_ADMIN_V1,
|
||||
filter!(f_eq("name", PartialValue::new_iname("flarbalgarble"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("description"),
|
||||
Value::from("anusaosu"),
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_nochg = ModifyEvent::new_impersonate_entry_ser(
|
||||
JSON_ADMIN_V1,
|
||||
filter!(f_eq("name", PartialValue::new_iname("flarbalgarble"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("description"),
|
||||
Value::from("anusaosu"),
|
||||
)]),
|
||||
);
|
||||
assert!(server_txn.modify(&me_nochg) == Err(OperationError::NoMatchingEntries));
|
||||
|
||||
// Filter is invalid to schema - to check this due to changes in the way events are
|
||||
|
@ -551,15 +547,13 @@ mod tests {
|
|||
);
|
||||
|
||||
// Mod is invalid to schema
|
||||
let me_inv_m = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_pres("class")),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("htnaonu"),
|
||||
Value::from("anusaosu"),
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_inv_m = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_pres("class")),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("htnaonu"),
|
||||
Value::from("anusaosu"),
|
||||
)]),
|
||||
);
|
||||
assert!(
|
||||
server_txn.modify(&me_inv_m)
|
||||
== Err(OperationError::SchemaViolation(
|
||||
|
@ -568,30 +562,26 @@ mod tests {
|
|||
);
|
||||
|
||||
// Mod single object
|
||||
let me_sin = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson2"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Purged(AttrString::from("description")),
|
||||
Modify::Present(AttrString::from("description"), Value::from("anusaosu")),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_sin = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson2"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Purged(AttrString::from("description")),
|
||||
Modify::Present(AttrString::from("description"), Value::from("anusaosu")),
|
||||
]),
|
||||
);
|
||||
assert!(server_txn.modify(&me_sin).is_ok());
|
||||
|
||||
// Mod multiple object
|
||||
let me_mult = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_or!([
|
||||
f_eq("name", PartialValue::new_iname("testperson1")),
|
||||
f_eq("name", PartialValue::new_iname("testperson2")),
|
||||
])),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Purged(AttrString::from("description")),
|
||||
Modify::Present(AttrString::from("description"), Value::from("anusaosu")),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_mult = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_or!([
|
||||
f_eq("name", PartialValue::new_iname("testperson1")),
|
||||
f_eq("name", PartialValue::new_iname("testperson2")),
|
||||
])),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Purged(AttrString::from("description")),
|
||||
Modify::Present(AttrString::from("description"), Value::from("anusaosu")),
|
||||
]),
|
||||
);
|
||||
assert!(server_txn.modify(&me_mult).is_ok());
|
||||
|
||||
assert!(server_txn.commit().is_ok());
|
||||
|
@ -659,52 +649,44 @@ mod tests {
|
|||
assert!(cr.is_ok());
|
||||
|
||||
// Add class but no values
|
||||
let me_sin = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("class"),
|
||||
Value::new_class("system_info"),
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_sin = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("class"),
|
||||
Value::new_class("system_info"),
|
||||
)]),
|
||||
);
|
||||
assert!(server_txn.modify(&me_sin).is_err());
|
||||
|
||||
// Add multivalue where not valid
|
||||
let me_sin = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("name"),
|
||||
Value::new_iname("testpersonx"),
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_sin = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("name"),
|
||||
Value::new_iname("testpersonx"),
|
||||
)]),
|
||||
);
|
||||
assert!(server_txn.modify(&me_sin).is_err());
|
||||
|
||||
// add class and valid values?
|
||||
let me_sin = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("system_info")),
|
||||
// Modify::Present("domain".to_string(), Value::new_iutf8("domain.name")),
|
||||
Modify::Present(AttrString::from("version"), Value::new_uint32(1)),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_sin = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Present(AttrString::from("class"), Value::new_class("system_info")),
|
||||
// Modify::Present("domain".to_string(), Value::new_iutf8("domain.name")),
|
||||
Modify::Present(AttrString::from("version"), Value::new_uint32(1)),
|
||||
]),
|
||||
);
|
||||
assert!(server_txn.modify(&me_sin).is_ok());
|
||||
|
||||
// Replace a value
|
||||
let me_sin = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Purged(AttrString::from("name")),
|
||||
Modify::Present(AttrString::from("name"), Value::new_iname("testpersonx")),
|
||||
]),
|
||||
)
|
||||
};
|
||||
let me_sin = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![
|
||||
Modify::Purged(AttrString::from("name")),
|
||||
Modify::Present(AttrString::from("name"), Value::new_iname("testpersonx")),
|
||||
]),
|
||||
);
|
||||
assert!(server_txn.modify(&me_sin).is_ok());
|
||||
}
|
||||
|
||||
|
@ -736,15 +718,13 @@ mod tests {
|
|||
assert!(v_cred.validate());
|
||||
|
||||
// now modify and provide a primary credential.
|
||||
let me_inv_m = unsafe {
|
||||
ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("primary_credential"),
|
||||
v_cred,
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_inv_m = ModifyEvent::new_internal_invalid(
|
||||
filter!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("primary_credential"),
|
||||
v_cred,
|
||||
)]),
|
||||
);
|
||||
// go!
|
||||
assert!(server_txn.modify(&me_inv_m).is_ok());
|
||||
|
||||
|
|
|
@ -258,31 +258,25 @@ mod tests {
|
|||
let filt_i_per = filter_all!(f_eq("class", PartialValue::new_class("person")));
|
||||
|
||||
// Create fake external requests. Probably from admin later
|
||||
let me_rc = unsafe {
|
||||
ModifyEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filt_i_rc.clone(),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("class"),
|
||||
Value::new_class("recycled"),
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_rc = ModifyEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filt_i_rc.clone(),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("class"),
|
||||
Value::new_class("recycled"),
|
||||
)]),
|
||||
);
|
||||
|
||||
let de_rc = unsafe { DeleteEvent::new_impersonate_entry(admin.clone(), filt_i_rc.clone()) };
|
||||
let de_rc = DeleteEvent::new_impersonate_entry(admin.clone(), filt_i_rc.clone());
|
||||
|
||||
let se_rc =
|
||||
unsafe { SearchEvent::new_ext_impersonate_entry(admin.clone(), filt_i_rc.clone()) };
|
||||
let se_rc = SearchEvent::new_ext_impersonate_entry(admin.clone(), filt_i_rc.clone());
|
||||
|
||||
let sre_rc =
|
||||
unsafe { SearchEvent::new_rec_impersonate_entry(admin.clone(), filt_i_rc.clone()) };
|
||||
let sre_rc = SearchEvent::new_rec_impersonate_entry(admin.clone(), filt_i_rc.clone());
|
||||
|
||||
let rre_rc = unsafe {
|
||||
ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin,
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
)
|
||||
};
|
||||
let rre_rc = ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin,
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
);
|
||||
|
||||
// Create some recycled objects
|
||||
let e1 = entry_init!(
|
||||
|
@ -314,12 +308,10 @@ mod tests {
|
|||
assert!(cr.is_ok());
|
||||
|
||||
// Now we immediately delete these to force them to the correct state.
|
||||
let de_sin = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_or!([
|
||||
f_eq("name", PartialValue::new_iname("testperson1")),
|
||||
f_eq("name", PartialValue::new_iname("testperson2")),
|
||||
])))
|
||||
};
|
||||
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_or!([
|
||||
f_eq("name", PartialValue::new_iname("testperson1")),
|
||||
f_eq("name", PartialValue::new_iname("testperson2")),
|
||||
])));
|
||||
assert!(server_txn.delete(&de_sin).is_ok());
|
||||
|
||||
// Can it be seen (external search)
|
||||
|
@ -409,16 +401,14 @@ mod tests {
|
|||
let cr = server_txn.create(&ce);
|
||||
assert!(cr.is_ok());
|
||||
// Delete and ensure they became recycled.
|
||||
let de_sin = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson1")
|
||||
)))
|
||||
};
|
||||
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson1")
|
||||
)));
|
||||
assert!(server_txn.delete(&de_sin).is_ok());
|
||||
// Can in be seen by special search? (external recycle search)
|
||||
let filt_rc = filter_all!(f_eq("class", PartialValue::new_class("recycled")));
|
||||
let sre_rc = unsafe { SearchEvent::new_rec_impersonate_entry(admin, filt_rc) };
|
||||
let sre_rc = SearchEvent::new_rec_impersonate_entry(admin, filt_rc);
|
||||
let r2 = server_txn.search(&sre_rc).expect("search failed");
|
||||
assert!(r2.len() == 1);
|
||||
|
||||
|
@ -463,12 +453,10 @@ mod tests {
|
|||
assert!(server_txn.name_to_uuid("testperson1") == Ok(tuuid));
|
||||
|
||||
// delete
|
||||
let de_sin = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson1")
|
||||
)))
|
||||
};
|
||||
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson1")
|
||||
)));
|
||||
assert!(server_txn.delete(&de_sin).is_ok());
|
||||
|
||||
// all should fail
|
||||
|
@ -483,12 +471,10 @@ mod tests {
|
|||
|
||||
// revive
|
||||
let admin = server_txn.internal_search_uuid(UUID_ADMIN).expect("failed");
|
||||
let rre_rc = unsafe {
|
||||
ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin,
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
)
|
||||
};
|
||||
let rre_rc = ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin,
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("testperson1"))),
|
||||
);
|
||||
assert!(server_txn.revive_recycled(&rre_rc).is_ok());
|
||||
|
||||
// all checks pass
|
||||
|
@ -518,19 +504,17 @@ mod tests {
|
|||
|
||||
// Create fake external requests. Probably from admin later
|
||||
// Should we do this with impersonate instead of using the external
|
||||
let me_ts = unsafe {
|
||||
ModifyEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filt_i_ts.clone(),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("class"),
|
||||
Value::new_class("tombstone"),
|
||||
)]),
|
||||
)
|
||||
};
|
||||
let me_ts = ModifyEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filt_i_ts.clone(),
|
||||
ModifyList::new_list(vec![Modify::Present(
|
||||
AttrString::from("class"),
|
||||
Value::new_class("tombstone"),
|
||||
)]),
|
||||
);
|
||||
|
||||
let de_ts = unsafe { DeleteEvent::new_impersonate_entry(admin.clone(), filt_i_ts.clone()) };
|
||||
let se_ts = unsafe { SearchEvent::new_ext_impersonate_entry(admin, filt_i_ts.clone()) };
|
||||
let de_ts = DeleteEvent::new_impersonate_entry(admin.clone(), filt_i_ts.clone());
|
||||
let se_ts = SearchEvent::new_ext_impersonate_entry(admin, filt_i_ts.clone());
|
||||
|
||||
// First, create an entry, then push it through the lifecycle.
|
||||
let e_ts = entry_init!(
|
||||
|
@ -549,12 +533,10 @@ mod tests {
|
|||
let cr = server_txn.create(&ce);
|
||||
assert!(cr.is_ok());
|
||||
|
||||
let de_sin = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson1")
|
||||
)])))
|
||||
};
|
||||
let de_sin = DeleteEvent::new_internal_invalid(filter!(f_or!([f_eq(
|
||||
"name",
|
||||
PartialValue::new_iname("testperson1")
|
||||
)])));
|
||||
assert!(server_txn.delete(&de_sin).is_ok());
|
||||
|
||||
// Commit
|
||||
|
@ -696,25 +678,21 @@ mod tests {
|
|||
assert!(cr.is_ok());
|
||||
|
||||
// Now recycle the needed entries.
|
||||
let de = unsafe {
|
||||
DeleteEvent::new_internal_invalid(filter!(f_or(vec![
|
||||
f_eq("name", PartialValue::new_iname("u1")),
|
||||
f_eq("name", PartialValue::new_iname("u2")),
|
||||
f_eq("name", PartialValue::new_iname("u3")),
|
||||
f_eq("name", PartialValue::new_iname("g3")),
|
||||
f_eq("name", PartialValue::new_iname("u4")),
|
||||
f_eq("name", PartialValue::new_iname("g4"))
|
||||
])))
|
||||
};
|
||||
let de = DeleteEvent::new_internal_invalid(filter!(f_or(vec![
|
||||
f_eq("name", PartialValue::new_iname("u1")),
|
||||
f_eq("name", PartialValue::new_iname("u2")),
|
||||
f_eq("name", PartialValue::new_iname("u3")),
|
||||
f_eq("name", PartialValue::new_iname("g3")),
|
||||
f_eq("name", PartialValue::new_iname("u4")),
|
||||
f_eq("name", PartialValue::new_iname("g4"))
|
||||
])));
|
||||
assert!(server_txn.delete(&de).is_ok());
|
||||
|
||||
// Now revive and check each one, one at a time.
|
||||
let rev1 = unsafe {
|
||||
ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("u1"))),
|
||||
)
|
||||
};
|
||||
let rev1 = ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("u1"))),
|
||||
);
|
||||
assert!(server_txn.revive_recycled(&rev1).is_ok());
|
||||
// check u1 contains MO ->
|
||||
assert!(check_entry_has_mo(
|
||||
|
@ -724,12 +702,10 @@ mod tests {
|
|||
));
|
||||
|
||||
// Revive u2 and check it has two mo.
|
||||
let rev2 = unsafe {
|
||||
ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("u2"))),
|
||||
)
|
||||
};
|
||||
let rev2 = ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("u2"))),
|
||||
);
|
||||
assert!(server_txn.revive_recycled(&rev2).is_ok());
|
||||
assert!(check_entry_has_mo(
|
||||
&mut server_txn,
|
||||
|
@ -743,15 +719,13 @@ mod tests {
|
|||
));
|
||||
|
||||
// Revive u3 and g3 at the same time.
|
||||
let rev3 = unsafe {
|
||||
ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filter_all!(f_or(vec![
|
||||
f_eq("name", PartialValue::new_iname("u3")),
|
||||
f_eq("name", PartialValue::new_iname("g3"))
|
||||
])),
|
||||
)
|
||||
};
|
||||
let rev3 = ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filter_all!(f_or(vec![
|
||||
f_eq("name", PartialValue::new_iname("u3")),
|
||||
f_eq("name", PartialValue::new_iname("g3"))
|
||||
])),
|
||||
);
|
||||
assert!(server_txn.revive_recycled(&rev3).is_ok());
|
||||
assert!(!check_entry_has_mo(
|
||||
&mut server_txn,
|
||||
|
@ -760,12 +734,10 @@ mod tests {
|
|||
));
|
||||
|
||||
// Revive u4, should NOT have the MO.
|
||||
let rev4a = unsafe {
|
||||
ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("u4"))),
|
||||
)
|
||||
};
|
||||
let rev4a = ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin.clone(),
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("u4"))),
|
||||
);
|
||||
assert!(server_txn.revive_recycled(&rev4a).is_ok());
|
||||
assert!(!check_entry_has_mo(
|
||||
&mut server_txn,
|
||||
|
@ -774,12 +746,10 @@ mod tests {
|
|||
));
|
||||
|
||||
// Now revive g4, should allow MO onto u4.
|
||||
let rev4b = unsafe {
|
||||
ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin,
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("g4"))),
|
||||
)
|
||||
};
|
||||
let rev4b = ReviveRecycledEvent::new_impersonate_entry(
|
||||
admin,
|
||||
filter_all!(f_eq("name", PartialValue::new_iname("g4"))),
|
||||
);
|
||||
assert!(server_txn.revive_recycled(&rev4b).is_ok());
|
||||
assert!(!check_entry_has_mo(
|
||||
&mut server_txn,
|
||||
|
|
|
@ -78,14 +78,6 @@ pub type ValueSet = Box<dyn ValueSetT + Send + Sync + 'static>;
|
|||
dyn_clone::clone_trait_object!(ValueSetT);
|
||||
|
||||
pub trait ValueSetT: std::fmt::Debug + DynClone {
|
||||
/// # Safety
|
||||
/// This is unsafe as you are unable to distinguish the case between
|
||||
/// the value already existing, OR the value being an incorrect type to add
|
||||
/// to the set.
|
||||
unsafe fn insert(&mut self, value: Value) -> bool {
|
||||
self.insert_checked(value).unwrap_or(false)
|
||||
}
|
||||
|
||||
fn insert_checked(&mut self, value: Value) -> Result<bool, OperationError>;
|
||||
|
||||
fn clear(&mut self);
|
||||
|
@ -577,9 +569,7 @@ pub fn uuid_to_proto_string(u: Uuid) -> String {
|
|||
pub fn from_result_value_iter(
|
||||
mut iter: impl Iterator<Item = Result<Value, OperationError>>,
|
||||
) -> Result<ValueSet, OperationError> {
|
||||
let init = if let Some(v) = iter.next() {
|
||||
v
|
||||
} else {
|
||||
let Some(init) = iter.next() else {
|
||||
admin_error!("Empty value iterator");
|
||||
return Err(OperationError::InvalidValueState);
|
||||
};
|
||||
|
@ -638,9 +628,7 @@ pub fn from_result_value_iter(
|
|||
}
|
||||
|
||||
pub fn from_value_iter(mut iter: impl Iterator<Item = Value>) -> Result<ValueSet, OperationError> {
|
||||
let init = if let Some(v) = iter.next() {
|
||||
v
|
||||
} else {
|
||||
let Some(init) = iter.next() else {
|
||||
admin_error!("Empty value iterator");
|
||||
return Err(OperationError::InvalidValueState);
|
||||
};
|
||||
|
|
|
@ -31,10 +31,7 @@ impl From<UnixUserToken> for UserToken {
|
|||
valid,
|
||||
} = value;
|
||||
|
||||
let groups = groups
|
||||
.into_iter()
|
||||
.map(GroupToken::from)
|
||||
.collect();
|
||||
let groups = groups.into_iter().map(GroupToken::from).collect();
|
||||
|
||||
UserToken {
|
||||
name,
|
||||
|
|
Loading…
Reference in a new issue