mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
during service account recovery, remove incompatible credentials (#1650)
This commit is contained in:
parent
21d372c09f
commit
0a16434bdc
|
@ -420,7 +420,7 @@ impl QueryServerWriteV1 {
|
||||||
e
|
e
|
||||||
})?;
|
})?;
|
||||||
idms_prox_write
|
idms_prox_write
|
||||||
.generate_account_password(&gpe)
|
.generate_service_account_password(&gpe)
|
||||||
.and_then(|r| idms_prox_write.commit().map(|_| r))
|
.and_then(|r| idms_prox_write.commit().map(|_| r))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -371,16 +371,6 @@ impl Account {
|
||||||
self.uuid == UUID_ANONYMOUS
|
self.uuid == UUID_ANONYMOUS
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn gen_generatedpassword_recover_mod(
|
|
||||||
&self,
|
|
||||||
cleartext: &str,
|
|
||||||
crypto_policy: &CryptoPolicy,
|
|
||||||
) -> Result<ModifyList<ModifyInvalid>, OperationError> {
|
|
||||||
let ncred = Credential::new_generatedpassword_only(crypto_policy, cleartext)?;
|
|
||||||
let vcred = Value::new_credential("primary", ncred);
|
|
||||||
Ok(ModifyList::new_purge_and_set("primary_credential", vcred))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn gen_password_mod(
|
pub(crate) fn gen_password_mod(
|
||||||
&self,
|
&self,
|
||||||
cleartext: &str,
|
cleartext: &str,
|
||||||
|
|
|
@ -27,7 +27,7 @@ use webauthn_rs::prelude::{Webauthn, WebauthnBuilder};
|
||||||
|
|
||||||
use super::event::ReadBackupCodeEvent;
|
use super::event::ReadBackupCodeEvent;
|
||||||
use super::ldap::{LdapBoundToken, LdapSession};
|
use super::ldap::{LdapBoundToken, LdapSession};
|
||||||
use crate::credential::softlock::CredSoftLock;
|
use crate::credential::{softlock::CredSoftLock, Credential};
|
||||||
use crate::idm::account::Account;
|
use crate::idm::account::Account;
|
||||||
use crate::idm::authsession::AuthSession;
|
use crate::idm::authsession::AuthSession;
|
||||||
use crate::idm::credupdatesession::CredentialUpdateSessionMutex;
|
use crate::idm::credupdatesession::CredentialUpdateSessionMutex;
|
||||||
|
@ -39,9 +39,9 @@ use crate::idm::delayed::{
|
||||||
use crate::idm::event::PasswordChangeEvent;
|
use crate::idm::event::PasswordChangeEvent;
|
||||||
use crate::idm::event::{AuthEvent, AuthEventStep, AuthResult};
|
use crate::idm::event::{AuthEvent, AuthEventStep, AuthResult};
|
||||||
use crate::idm::event::{
|
use crate::idm::event::{
|
||||||
CredentialStatusEvent, GeneratePasswordEvent, LdapAuthEvent, LdapTokenAuthEvent,
|
CredentialStatusEvent, LdapAuthEvent, LdapTokenAuthEvent, RadiusAuthTokenEvent,
|
||||||
RadiusAuthTokenEvent, RegenerateRadiusSecretEvent, UnixGroupTokenEvent,
|
RegenerateRadiusSecretEvent, UnixGroupTokenEvent, UnixPasswordChangeEvent, UnixUserAuthEvent,
|
||||||
UnixPasswordChangeEvent, UnixUserAuthEvent, UnixUserTokenEvent,
|
UnixUserTokenEvent,
|
||||||
};
|
};
|
||||||
use crate::idm::oauth2::{
|
use crate::idm::oauth2::{
|
||||||
Oauth2ResourceServers, Oauth2ResourceServersReadTransaction,
|
Oauth2ResourceServers, Oauth2ResourceServersReadTransaction,
|
||||||
|
@ -1478,6 +1478,10 @@ impl<'a> IdmServerTransaction<'a> for IdmServerProxyWriteTransaction<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IdmServerProxyWriteTransaction<'a> {
|
impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
|
pub(crate) fn crypto_policy(&self) -> &CryptoPolicy {
|
||||||
|
self.crypto_policy
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_origin(&self) -> &Url {
|
pub fn get_origin(&self) -> &Url {
|
||||||
#[allow(clippy::unwrap_used)]
|
#[allow(clippy::unwrap_used)]
|
||||||
self.webauthn.get_allowed_origins().get(0).unwrap()
|
self.webauthn.get_allowed_origins().get(0).unwrap()
|
||||||
|
@ -1716,18 +1720,23 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
e
|
e
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let account = self.target_to_account(target)?;
|
|
||||||
|
|
||||||
let cleartext = cleartext
|
let cleartext = cleartext
|
||||||
.map(|s| s.to_string())
|
.map(|s| s.to_string())
|
||||||
.unwrap_or_else(password_from_random);
|
.unwrap_or_else(password_from_random);
|
||||||
|
|
||||||
let modlist = account
|
let ncred = Credential::new_generatedpassword_only(self.crypto_policy, &cleartext)
|
||||||
.gen_generatedpassword_recover_mod(&cleartext, self.crypto_policy)
|
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
admin_error!("Failed to generate password mod {:?}", e);
|
admin_error!("Unable to generate password mod {:?}", e);
|
||||||
e
|
e
|
||||||
})?;
|
})?;
|
||||||
|
let vcred = Value::new_credential("primary", ncred);
|
||||||
|
// We need to remove other credentials too.
|
||||||
|
let modlist = ModifyList::new_list(vec![
|
||||||
|
m_purge("passkeys"),
|
||||||
|
m_purge("primary_credential"),
|
||||||
|
Modify::Present("primary_credential".into(), vcred),
|
||||||
|
]);
|
||||||
|
|
||||||
trace!(?modlist, "processing change");
|
trace!(?modlist, "processing change");
|
||||||
|
|
||||||
self.qs_write
|
self.qs_write
|
||||||
|
@ -1744,116 +1753,6 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
Ok(cleartext)
|
Ok(cleartext)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_account_password(
|
|
||||||
&mut self,
|
|
||||||
gpe: &GeneratePasswordEvent,
|
|
||||||
) -> Result<String, OperationError> {
|
|
||||||
let account = self.target_to_account(gpe.target)?;
|
|
||||||
// Ask if tis all good - this step checks pwpolicy and such
|
|
||||||
|
|
||||||
// Generate a new random, long pw.
|
|
||||||
// Because this is generated, we can bypass policy checks!
|
|
||||||
let cleartext = password_from_random();
|
|
||||||
|
|
||||||
// check a password badlist - even if generated, we still don't want to
|
|
||||||
// reuse something that has been disclosed.
|
|
||||||
|
|
||||||
// it returns a modify
|
|
||||||
let modlist = account
|
|
||||||
.gen_generatedpassword_recover_mod(cleartext.as_str(), self.crypto_policy)
|
|
||||||
.map_err(|e| {
|
|
||||||
admin_error!("Unable to generate password mod {:?}", e);
|
|
||||||
e
|
|
||||||
})?;
|
|
||||||
|
|
||||||
trace!(?modlist, "processing change");
|
|
||||||
// given the new credential generate a modify
|
|
||||||
// We use impersonate here to get the event from ae
|
|
||||||
self.qs_write
|
|
||||||
.impersonate_modify(
|
|
||||||
// Filter as executed
|
|
||||||
&filter!(f_eq("uuid", PartialValue::Uuid(gpe.target))),
|
|
||||||
// Filter as intended (acp)
|
|
||||||
&filter_all!(f_eq("uuid", PartialValue::Uuid(gpe.target))),
|
|
||||||
&modlist,
|
|
||||||
// Provide the event to impersonate
|
|
||||||
&gpe.ident,
|
|
||||||
)
|
|
||||||
.map(|_| cleartext)
|
|
||||||
.map_err(|e| {
|
|
||||||
admin_error!("Failed to generate account password {:?}", e);
|
|
||||||
e
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
/// Generate a new set of backup code and remove the old ones.
|
|
||||||
pub(crate) fn generate_backup_code(
|
|
||||||
&mut self,
|
|
||||||
gbe: &GenerateBackupCodeEvent,
|
|
||||||
) -> Result<Vec<String>, OperationError> {
|
|
||||||
let account = self.target_to_account(&gbe.target)?;
|
|
||||||
|
|
||||||
// Generate a new set of backup code.
|
|
||||||
let s = backup_code_from_random();
|
|
||||||
|
|
||||||
// it returns a modify
|
|
||||||
let modlist = account
|
|
||||||
.gen_backup_code_mod(BackupCodes::new(s.clone()))
|
|
||||||
.map_err(|e| {
|
|
||||||
admin_error!("Unable to generate backup code mod {:?}", e);
|
|
||||||
e
|
|
||||||
})?;
|
|
||||||
|
|
||||||
trace!(?modlist, "processing change");
|
|
||||||
// given the new credential generate a modify
|
|
||||||
// We use impersonate here to get the event from ae
|
|
||||||
self.qs_write
|
|
||||||
.impersonate_modify(
|
|
||||||
// Filter as executed
|
|
||||||
&filter!(f_eq("uuid", PartialValue::Uuid(gbe.target))),
|
|
||||||
// Filter as intended (acp)
|
|
||||||
&filter_all!(f_eq("uuid", PartialValue::Uuid(gbe.target))),
|
|
||||||
&modlist,
|
|
||||||
// Provide the event to impersonate
|
|
||||||
&gbe.ident,
|
|
||||||
)
|
|
||||||
.map(|_| s.into_iter().collect())
|
|
||||||
.map_err(|e| {
|
|
||||||
admin_error!("Failed to generate backup code {:?}", e);
|
|
||||||
e
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn remove_backup_code(
|
|
||||||
&mut self,
|
|
||||||
rte: &RemoveBackupCodeEvent,
|
|
||||||
) -> Result<SetCredentialResponse, OperationError> {
|
|
||||||
trace!(target = ?rte.target, "Attempting to remove backup code");
|
|
||||||
|
|
||||||
let account = self.target_to_account(&rte.target)?;
|
|
||||||
let modlist = account.gen_backup_code_remove_mod().map_err(|e| {
|
|
||||||
admin_error!("Failed to gen backup code remove mod {:?}", e);
|
|
||||||
e
|
|
||||||
})?;
|
|
||||||
// Perform the mod
|
|
||||||
self.qs_write
|
|
||||||
.impersonate_modify(
|
|
||||||
// Filter as executed
|
|
||||||
&filter!(f_eq("uuid", PartialValue::Uuid(account.uuid))),
|
|
||||||
// Filter as intended (acp)
|
|
||||||
&filter_all!(f_eq("uuid", PartialValue::Uuid(account.uuid))),
|
|
||||||
&modlist,
|
|
||||||
&rte.ident,
|
|
||||||
)
|
|
||||||
.map_err(|e| {
|
|
||||||
admin_error!("remove_backup_code {:?}", e);
|
|
||||||
e
|
|
||||||
})
|
|
||||||
.map(|_| SetCredentialResponse::Success)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
pub fn regenerate_radius_secret(
|
pub fn regenerate_radius_secret(
|
||||||
&mut self,
|
&mut self,
|
||||||
rrse: &RegenerateRadiusSecretEvent,
|
rrse: &RegenerateRadiusSecretEvent,
|
||||||
|
|
|
@ -5,10 +5,13 @@ use compact_jwt::{Jws, JwsSigner};
|
||||||
use kanidm_proto::v1::ApiToken as ProtoApiToken;
|
use kanidm_proto::v1::ApiToken as ProtoApiToken;
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
|
|
||||||
|
use crate::credential::Credential;
|
||||||
use crate::event::SearchEvent;
|
use crate::event::SearchEvent;
|
||||||
use crate::idm::account::Account;
|
use crate::idm::account::Account;
|
||||||
|
use crate::idm::event::GeneratePasswordEvent;
|
||||||
use crate::idm::server::{IdmServerProxyReadTransaction, IdmServerProxyWriteTransaction};
|
use crate::idm::server::{IdmServerProxyReadTransaction, IdmServerProxyWriteTransaction};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
use crate::utils::password_from_random;
|
||||||
use crate::value::ApiToken;
|
use crate::value::ApiToken;
|
||||||
|
|
||||||
// Need to add KID to es256 der for lookups ✅
|
// Need to add KID to es256 der for lookups ✅
|
||||||
|
@ -305,6 +308,46 @@ impl<'a> IdmServerProxyWriteTransaction<'a> {
|
||||||
e
|
e
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn generate_service_account_password(
|
||||||
|
&mut self,
|
||||||
|
gpe: &GeneratePasswordEvent,
|
||||||
|
) -> Result<String, OperationError> {
|
||||||
|
// Generate a new random, long pw.
|
||||||
|
// Because this is generated, we can bypass policy checks!
|
||||||
|
let cleartext = password_from_random();
|
||||||
|
let ncred = Credential::new_generatedpassword_only(self.crypto_policy(), &cleartext)
|
||||||
|
.map_err(|e| {
|
||||||
|
admin_error!("Unable to generate password mod {:?}", e);
|
||||||
|
e
|
||||||
|
})?;
|
||||||
|
let vcred = Value::new_credential("primary", ncred);
|
||||||
|
// We need to remove other credentials too.
|
||||||
|
let modlist = ModifyList::new_list(vec![
|
||||||
|
m_purge("passkeys"),
|
||||||
|
m_purge("primary_credential"),
|
||||||
|
Modify::Present("primary_credential".into(), vcred),
|
||||||
|
]);
|
||||||
|
|
||||||
|
trace!(?modlist, "processing change");
|
||||||
|
// given the new credential generate a modify
|
||||||
|
// We use impersonate here to get the event from ae
|
||||||
|
self.qs_write
|
||||||
|
.impersonate_modify(
|
||||||
|
// Filter as executed
|
||||||
|
&filter!(f_eq("uuid", PartialValue::Uuid(gpe.target))),
|
||||||
|
// Filter as intended (acp)
|
||||||
|
&filter_all!(f_eq("uuid", PartialValue::Uuid(gpe.target))),
|
||||||
|
&modlist,
|
||||||
|
// Provide the event to impersonate
|
||||||
|
&gpe.ident,
|
||||||
|
)
|
||||||
|
.map(|_| cleartext)
|
||||||
|
.map_err(|e| {
|
||||||
|
admin_error!("Failed to generate account password {:?}", e);
|
||||||
|
e
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> IdmServerProxyReadTransaction<'a> {
|
impl<'a> IdmServerProxyReadTransaction<'a> {
|
||||||
|
|
Loading…
Reference in a new issue