mirror of
https://github.com/kanidm/kanidm.git
synced 2025-05-05 00:25:05 +02:00
Merge ce1cf544a2
into be4818e121
This commit is contained in:
commit
7ca02cde00
|
@ -6,6 +6,10 @@ use kanidm_proto::v1::{AccountUnixExtend, Entry, SingleStringRequest, UatStatus}
|
|||
use uuid::Uuid;
|
||||
|
||||
use crate::{ClientError, KanidmClient};
|
||||
use kanidm_proto::scim_v1::PatchRequest;
|
||||
use serde_json::Value;
|
||||
|
||||
use tracing::trace;
|
||||
|
||||
impl KanidmClient {
|
||||
pub async fn idm_person_account_list(&self) -> Result<Vec<Entry>, ClientError> {
|
||||
|
@ -286,4 +290,16 @@ impl KanidmClient {
|
|||
self.perform_post_request(format!("/v1/person/{}/_certificate", id).as_str(), new_cert)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn idm_person_account_patch(
|
||||
&self,
|
||||
id: &str,
|
||||
patch_request: PatchRequest,
|
||||
) -> Result<(), ClientError> {
|
||||
if patch_request.operations.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
self.perform_patch_request_scim(format!("/v1/person/{}", id).as_str(), patch_request)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,36 @@ use crate::{
|
|||
AccountSsh, AccountUserAuthToken, AccountValidity, OutputMode, PersonOpt, PersonPosix,
|
||||
};
|
||||
|
||||
use kanidm_client::ClientError;
|
||||
use kanidm_client::OutputFormat;
|
||||
use kanidm_client::SSHKEY_ATTEST_FEATURE;
|
||||
use kanidm_proto::identity::v1::{
|
||||
IdentityGetReply, KeyAttestationVerifyRequest, KeyType as SSHKeyAttestationType,
|
||||
};
|
||||
use kanidm_proto::identity::{self};
|
||||
use kanidm_proto::internal::{
|
||||
CUCredState, CURegState, CURegWarning, CURequest, CUSessionToken, CUStatus, CredentialDetail,
|
||||
PasskeyDetail, SshPublicKey, TotpSecret,
|
||||
};
|
||||
use kanidm_proto::scim_v1::{
|
||||
client::{ScimSshPublicKeys, PATCHOP_SCHEMA_URI},
|
||||
PatchOp, PatchOperation, PatchRequest, ScimEntryGetQuery,
|
||||
ATTR_DISPLAYNAME, ATTR_GIDNUMBER, ATTR_LEGALNAME, ATTR_MAIL, ATTR_NAME, ATTR_PASSWORD, ATTR_POSIXACCOUNTS,
|
||||
ATTR_SSH_PUBLICKEY,
|
||||
};
|
||||
use kanidm_proto::MessageError;
|
||||
use serde_json::json;
|
||||
use sshkey_attest::{Error as AttestationError, RegisterChallengeResponse};
|
||||
use sshkeys::PublicKey as ActualSshPublicKey;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use dialoguer::Input;
|
||||
use tracing::{debug, error, info, trace, warn};
|
||||
use uuid::Uuid;
|
||||
|
||||
impl PersonOpt {
|
||||
pub fn debug(&self) -> bool {
|
||||
match self {
|
||||
|
@ -321,14 +351,71 @@ impl PersonOpt {
|
|||
}
|
||||
PersonOpt::Update(aopt) => {
|
||||
let client = aopt.copt.to_client(OpType::Write).await;
|
||||
|
||||
let mut patch_ops = Vec::new();
|
||||
|
||||
// Helper to create a replace operation
|
||||
let replace_op = |path: &str, value: &str| -> PatchOperation {
|
||||
PatchOperation {
|
||||
op: PatchOp::Replace,
|
||||
path: Some(path.to_string()),
|
||||
value: Some(json!(value)),
|
||||
}
|
||||
};
|
||||
|
||||
// Helper to create a replace operation for Vec<String>
|
||||
let replace_op_vec = |path: &str, value: &[String]| -> PatchOperation {
|
||||
PatchOperation {
|
||||
op: PatchOp::Replace,
|
||||
path: Some(path.to_string()),
|
||||
value: Some(json!(value)),
|
||||
}
|
||||
};
|
||||
|
||||
// Helper to create a remove operation
|
||||
let remove_op = |path: &str| -> PatchOperation {
|
||||
PatchOperation {
|
||||
op: PatchOp::Remove,
|
||||
path: Some(path.to_string()),
|
||||
value: None,
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(newname) = &aopt.newname {
|
||||
patch_ops.push(replace_op(ATTR_NAME, newname));
|
||||
}
|
||||
if let Some(displayname) = &aopt.displayname {
|
||||
patch_ops.push(replace_op(ATTR_DISPLAYNAME, displayname));
|
||||
}
|
||||
if let Some(legalname) = &aopt.legalname {
|
||||
if legalname.is_empty() {
|
||||
// Empty string means clear the attribute
|
||||
patch_ops.push(remove_op(ATTR_LEGALNAME));
|
||||
} else {
|
||||
patch_ops.push(replace_op(ATTR_LEGALNAME, legalname));
|
||||
}
|
||||
}
|
||||
if let Some(mail) = &aopt.mail {
|
||||
if mail.is_empty() {
|
||||
// Empty list means clear the attribute
|
||||
patch_ops.push(remove_op(ATTR_MAIL));
|
||||
} else {
|
||||
patch_ops.push(replace_op_vec(ATTR_MAIL, mail));
|
||||
}
|
||||
}
|
||||
|
||||
if patch_ops.is_empty() {
|
||||
println!("No changes specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
let patch_request = PatchRequest {
|
||||
schemas: vec![PATCHOP_SCHEMA_URI.to_string()],
|
||||
operations: patch_ops,
|
||||
};
|
||||
|
||||
match client
|
||||
.idm_person_account_update(
|
||||
aopt.aopts.account_id.as_str(),
|
||||
aopt.newname.as_deref(),
|
||||
aopt.displayname.as_deref(),
|
||||
aopt.legalname.as_deref(),
|
||||
aopt.mail.as_deref(),
|
||||
)
|
||||
.idm_person_account_patch(aopt.aopts.account_id.as_str(), patch_request)
|
||||
.await
|
||||
{
|
||||
Ok(()) => println!("Success"),
|
||||
|
|
|
@ -594,8 +594,7 @@ pub enum ServiceAccountPosix {
|
|||
pub struct PersonUpdateOpt {
|
||||
#[clap(flatten)]
|
||||
aopts: AccountCommonOpt,
|
||||
#[clap(long, short, help = "Set the legal name for the person.",
|
||||
value_parser = clap::builder::NonEmptyStringValueParser::new())]
|
||||
#[clap(long, short, help = "Set the legal name for the person. Use '' to clear.")]
|
||||
legalname: Option<String>,
|
||||
#[clap(long, short, help = "Set the account name for the person.",
|
||||
value_parser = clap::builder::NonEmptyStringValueParser::new())]
|
||||
|
|
Loading…
Reference in a new issue