mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
parent
17741c4929
commit
f6001504a9
|
@ -585,7 +585,7 @@ lazy_static! {
|
|||
"description",
|
||||
Value::new_utf8s("System (local) info and metadata object.")
|
||||
),
|
||||
("version", Value::Uint32(14))
|
||||
("version", Value::Uint32(15))
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -549,8 +549,8 @@ pub static ref SCHEMA_CLASS_PERSON: SchemaClass = SchemaClass {
|
|||
description: "Object representation of a person".to_string(),
|
||||
|
||||
sync_allowed: true,
|
||||
systemmay: attrstring_vec!(["mail", "legalname", "id_verification_eckey"]),
|
||||
systemmust: attrstring_vec!(["displayname", "name"]),
|
||||
systemmay: attrstring_vec!(["mail", "legalname"]),
|
||||
systemmust: attrstring_vec!(["displayname", "name", "id_verification_eckey"]),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
|
|
|
@ -1,54 +1,39 @@
|
|||
use openssl::ec::{EcGroup, EcKey};
|
||||
use openssl::nid::Nid;
|
||||
use sketching::{admin_error, security_info};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use super::Plugin;
|
||||
use crate::event::{CreateEvent, ModifyEvent};
|
||||
use crate::modify::{ModifyList, ModifyValid};
|
||||
use crate::prelude::{BatchModifyEvent, EntryInvalidCommitted, Modify};
|
||||
use crate::prelude::{Entry, EntryInvalid, EntryInvalidNew, OperationError};
|
||||
use crate::server::QueryServerWriteTransaction;
|
||||
use crate::value::PartialValue;
|
||||
use sketching::tagged_event;
|
||||
use sketching::EventTag;
|
||||
|
||||
lazy_static! {
|
||||
// it contains all the partialvalues used to match against an Entry's class,
|
||||
// we need ALL partialvalues to match in order to target the entry
|
||||
static ref CLASSES_TO_UPDATE: [PartialValue; 3] = [PartialValue::new_iutf8("account"), PartialValue::new_iutf8("person"), PartialValue::new_iutf8("object")];
|
||||
|
||||
static ref DEFAULT_KEY_GROUP: EcGroup = {
|
||||
let nid = Nid::X9_62_PRIME256V1; // NIST P-256 curve
|
||||
#[allow(clippy::unwrap_used)]
|
||||
EcGroup::from_curve_name(nid).unwrap()
|
||||
};
|
||||
}
|
||||
|
||||
pub struct EcdhKeyGen {}
|
||||
|
||||
impl EcdhKeyGen {
|
||||
fn is_entry_to_update<VALUE, STATE>(entry: &mut Entry<VALUE, STATE>) -> bool {
|
||||
CLASSES_TO_UPDATE
|
||||
.iter()
|
||||
.all(|pv| entry.attribute_equality("class", pv))
|
||||
}
|
||||
// we optionally provide a target_cand to update only the entry with the given uuid
|
||||
fn generate_key<STATE: Clone>(
|
||||
cands: &mut [Entry<EntryInvalid, STATE>],
|
||||
target_cand: Option<Uuid>,
|
||||
) -> Result<(), OperationError> {
|
||||
for cand in cands.iter_mut() {
|
||||
if Self::is_entry_to_update(cand) {
|
||||
if let (Some(target_cand), Some(current_uuid)) = (target_cand, cand.get_uuid()) {
|
||||
if target_cand != current_uuid {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if cand.attribute_equality("class", &PVCLASS_PERSON)
|
||||
&& !cand.attribute_pres("id_verification_eckey")
|
||||
{
|
||||
debug!("Generating idv_eckey for {}", cand.get_display_id());
|
||||
|
||||
let new_private_key = EcKey::generate(&DEFAULT_KEY_GROUP).map_err(|e| {
|
||||
admin_error!(err = ?e, "Unable to generate identification ECDH private key");
|
||||
error!(err = ?e, "Unable to generate id verification ECDH private key");
|
||||
OperationError::CryptographyError
|
||||
})?;
|
||||
cand.add_ava_if_not_exist(
|
||||
|
||||
cand.add_ava(
|
||||
"id_verification_eckey",
|
||||
crate::value::Value::EcKeyPrivate(new_private_key),
|
||||
)
|
||||
|
@ -56,49 +41,6 @@ impl EcdhKeyGen {
|
|||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_modify(
|
||||
cands: &mut [EntryInvalidCommitted],
|
||||
me: &ModifyEvent,
|
||||
) -> Result<(), OperationError> {
|
||||
if Self::should_regenerate_ecdh_key(&me.modlist)? {
|
||||
security_info!("regenerating personal ecdh secret");
|
||||
Self::generate_key(cands, None)?;
|
||||
};
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_batch_modify(
|
||||
cands: &mut [EntryInvalidCommitted],
|
||||
me: &BatchModifyEvent,
|
||||
) -> Result<(), OperationError> {
|
||||
for (uuid, modlist) in me.modset.iter() {
|
||||
if Self::should_regenerate_ecdh_key(modlist)? {
|
||||
security_info!("regenerating personal ecdh secret");
|
||||
Self::generate_key(cands, Some(*uuid))?;
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn should_regenerate_ecdh_key(
|
||||
modlist: &ModifyList<ModifyValid>,
|
||||
) -> Result<bool, OperationError> {
|
||||
let modify_present_attempted = modlist.iter().any(|m| match m {
|
||||
Modify::Present(a, _) => a == "id_verification_eckey",
|
||||
_ => false,
|
||||
});
|
||||
if modify_present_attempted {
|
||||
Err(OperationError::SystemProtectedAttribute)
|
||||
} else {
|
||||
let should_regenerate_ecdh_key = modlist.iter().any(|m| match m {
|
||||
Modify::Purged(a) | Modify::Removed(a, _) => a == "id_verification_eckey",
|
||||
_ => false,
|
||||
});
|
||||
Ok(should_regenerate_ecdh_key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Plugin for EcdhKeyGen {
|
||||
|
@ -106,30 +48,33 @@ impl Plugin for EcdhKeyGen {
|
|||
"plugin_ecdhkey_gen"
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", name = "ecdhkeygen::pre_create_transform", skip_all)]
|
||||
fn pre_create_transform(
|
||||
_qs: &mut QueryServerWriteTransaction,
|
||||
cand: &mut Vec<EntryInvalidNew>,
|
||||
_ce: &CreateEvent,
|
||||
) -> Result<(), OperationError> {
|
||||
Self::generate_key(cand, None)
|
||||
Self::generate_key(cand)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", name = "ecdhkeygen::pre_modify", skip_all)]
|
||||
fn pre_modify(
|
||||
_qs: &mut crate::server::QueryServerWriteTransaction,
|
||||
_pre_cand: &[std::sync::Arc<crate::prelude::EntrySealedCommitted>],
|
||||
cand: &mut Vec<crate::prelude::EntryInvalidCommitted>,
|
||||
me: &crate::event::ModifyEvent,
|
||||
_me: &crate::event::ModifyEvent,
|
||||
) -> Result<(), kanidm_proto::v1::OperationError> {
|
||||
Self::handle_modify(cand, me)
|
||||
Self::generate_key(cand)
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", name = "ecdhkeygen::pre_batch_modify", skip_all)]
|
||||
fn pre_batch_modify(
|
||||
_qs: &mut crate::server::QueryServerWriteTransaction,
|
||||
_pre_cand: &[std::sync::Arc<crate::prelude::EntrySealedCommitted>],
|
||||
cand: &mut Vec<crate::prelude::EntryInvalidCommitted>,
|
||||
me: &crate::server::batch_modify::BatchModifyEvent,
|
||||
_me: &crate::server::batch_modify::BatchModifyEvent,
|
||||
) -> Result<(), kanidm_proto::v1::OperationError> {
|
||||
Self::handle_batch_modify(cand, me)
|
||||
Self::generate_key(cand)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -175,6 +120,9 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
/*
|
||||
// Invalid, can't be set due to no impl from clone_value
|
||||
|
||||
#[test]
|
||||
fn test_modify_present_ecdkey() {
|
||||
let ea = entry_init!(
|
||||
|
@ -200,6 +148,7 @@ mod tests {
|
|||
|_| {}
|
||||
);
|
||||
}
|
||||
*/
|
||||
|
||||
#[test]
|
||||
fn test_modify_purge_eckey() {
|
||||
|
|
|
@ -28,6 +28,7 @@ lazy_static! {
|
|||
m.insert("domain_ldap_basedn");
|
||||
m.insert("fernet_private_key_str");
|
||||
m.insert("es256_private_key_der");
|
||||
m.insert("id_verification_eckey");
|
||||
m.insert("badlist_password");
|
||||
m.insert("domain_display_name");
|
||||
m
|
||||
|
|
|
@ -1500,6 +1500,7 @@ async fn test_repl_increment_schema_conflict(server_a: &QueryServer, server_b: &
|
|||
let modlist = ModifyList::new_list(vec![
|
||||
Modify::Removed("class".into(), PVCLASS_PERSON.clone()),
|
||||
Modify::Present("class".into(), CLASS_GROUP.clone()),
|
||||
Modify::Purged("id_verification_eckey".into()),
|
||||
Modify::Purged("displayname".into()),
|
||||
]);
|
||||
assert!(server_b_txn.internal_modify_uuid(t_uuid, &modlist).is_ok());
|
||||
|
|
|
@ -107,6 +107,10 @@ impl QueryServer {
|
|||
if system_info_version < 14 {
|
||||
write_txn.migrate_13_to_14()?;
|
||||
}
|
||||
|
||||
if system_info_version < 15 {
|
||||
write_txn.migrate_14_to_15()?;
|
||||
}
|
||||
}
|
||||
|
||||
write_txn.reload()?;
|
||||
|
@ -421,6 +425,17 @@ impl<'a> QueryServerWriteTransaction<'a> {
|
|||
// Complete
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn migrate_14_to_15(&mut self) -> Result<(), OperationError> {
|
||||
admin_warn!("starting 14 to 15 migration.");
|
||||
let filter = filter!(f_eq("class", PVCLASS_PERSON.clone()));
|
||||
// Delete the non-existing attr for idv private key which triggers
|
||||
// it to regen.
|
||||
let modlist = ModifyList::new_purge("id_verification_eckey");
|
||||
self.internal_modify(&filter, &modlist)
|
||||
// Complete
|
||||
}
|
||||
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
pub fn initialise_schema_core(&mut self) -> Result<(), OperationError> {
|
||||
admin_debug!("initialise_schema_core -> start ...");
|
||||
|
|
Loading…
Reference in a new issue