kanidm_1_7: init at 1.7.1 (#430205)

+2
nixos/modules/services/security/kanidm.nix
···
};
config = mkIf (cfg.enableClient || cfg.enableServer || cfg.enablePam) {
+
warnings = lib.optionals (cfg.package.eolMessage != "") [ cfg.package.eolMessage ];
+
assertions =
let
entityList =
+12 -2
nixos/tests/all-tests.nix
···
k3s = handleTest ./k3s { };
kafka = handleTest ./kafka { };
kanboard = runTest ./web-apps/kanboard.nix;
-
kanidm = runTest ./kanidm.nix;
-
kanidm-provisioning = runTest ./kanidm-provisioning.nix;
+
kanidm =
+
kanidmVersion:
+
runTest {
+
imports = [ ./kanidm.nix ];
+
_module.args = { inherit kanidmVersion; };
+
};
+
kanidm-provisioning =
+
kanidmVersion:
+
runTest {
+
imports = [ ./kanidm-provisioning.nix ];
+
_module.args = { inherit kanidmVersion; };
+
};
karma = runTest ./karma.nix;
kavita = runTest ./kavita.nix;
kbd-setfont-decompress = runTest ./kbd-setfont-decompress.nix;
+9 -7
nixos/tests/kanidm-provisioning.nix
···
-
{ pkgs, ... }:
+
{ kanidmVersion, pkgs, ... }:
let
certs = import ./common/acme/server/snakeoil-certs.nix;
serverDomain = certs.domain;
···
provisionAdminPassword = "very-strong-password-for-admin";
provisionIdmAdminPassword = "very-strong-password-for-idm-admin";
provisionIdmAdminPassword2 = "very-strong-alternative-password-for-idm-admin";
+
+
kanidmPackage = pkgs."kanidmWithSecretProvisioning_${kanidmVersion}";
in
{
name = "kanidm-provisioning";
···
{ pkgs, lib, ... }:
{
services.kanidm = {
-
package = pkgs.kanidmWithSecretProvisioning_1_6;
+
package = kanidmPackage;
enableServer = true;
serverSettings = {
origin = "https://${serverDomain}";
···
users.users.kanidm.shell = pkgs.bashInteractive;
-
environment.systemPackages = with pkgs; [
-
kanidm
-
openldap
-
ripgrep
-
jq
+
environment.systemPackages = [
+
kanidmPackage
+
pkgs.openldap
+
pkgs.ripgrep
+
pkgs.jq
];
};
+9 -7
nixos/tests/kanidm.nix
···
-
{ pkgs, ... }:
+
{ kanidmVersion, pkgs, ... }:
let
certs = import ./common/acme/server/snakeoil-certs.nix;
serverDomain = certs.domain;
···
cp ${certs."${serverDomain}".cert} $out/snakeoil.crt
cp ${certs."${serverDomain}".key} $out/snakeoil.key
'';
+
+
kanidmPackage = pkgs."kanidm_${kanidmVersion}";
in
{
name = "kanidm";
···
{ pkgs, ... }:
{
services.kanidm = {
-
package = pkgs.kanidm_1_6;
+
package = kanidmPackage;
enableServer = true;
serverSettings = {
origin = "https://${serverDomain}";
···
users.users.kanidm.shell = pkgs.bashInteractive;
-
environment.systemPackages = with pkgs; [
-
kanidm
-
openldap
-
ripgrep
+
environment.systemPackages = [
+
kanidmPackage
+
pkgs.openldap
+
pkgs.ripgrep
];
};
···
{ nodes, ... }:
{
services.kanidm = {
-
package = pkgs.kanidm_1_6;
+
package = kanidmPackage;
enableClient = true;
clientSettings = {
uri = "https://${serverDomain}";
-1
pkgs/by-name/ka/kanidm/1_5.nix
···
version = "1.5.0";
hash = "sha256-swrqyjA7Wgq17vd+753LDFcXrSFixVNLhTvj1bhG3DU=";
cargoHash = "sha256-72IwS8Nk1y6xDH9y8JW2LpbhFWaq0tpORx7JQSCF5/M=";
-
patchDir = ./patches/1_5;
unsupported = true;
}
+1 -1
pkgs/by-name/ka/kanidm/1_6.nix
···
version = "1.6.4";
hash = "sha256-ui3w1HDHXHARsjQ3WtJfZbM7Xgg3ODnUneXJMQwaOMw=";
cargoHash = "sha256-KJGELBzScwsLd6g3GR9Vk0nfDU2EjZBfXwlXJ+bZb1k=";
-
patchDir = ./patches/1_6;
+
eolDate = "2025-09-01";
}
+5
pkgs/by-name/ka/kanidm/1_7.nix
···
+
import ./generic.nix {
+
version = "1.7.1";
+
hash = "sha256-CG4s6fYxTM2I/kFjD905g8/DSFkyB+0pnGVXgyRXtlE=";
+
cargoHash = "sha256-9bE3hSCFBJF8f3Lm5SzEuDtEpJBbCBijUDfqGiPnRsc=";
+
}
+1
pkgs/by-name/ka/kanidm/README.md
···
1. `cp -r pkgs/by-name/ka/kanidm/patches/1_4 pkgs/by-name/ka/kanidm/patches/1_5`
1. Update `1_5.nix` hashes/paths, and as needed for upstream changes, `generic.nix`
1. Update `all-packages.nix` to add `kanidm_1_5` and `kanidmWithSecretProvisioning_1_5`, leave default
+
1. Update the previous release, e.g. `1_4.nix` and set `eolDate = "YYYY-MM-DD"` where the date is 30 days from release of 1.5.
1. Create commit, `kanidm_1_5: init at 1.5.0` - this is the only commit that will be backported
### Update default
+51 -54
pkgs/by-name/ka/kanidm/generic.nix
···
version,
hash,
cargoHash,
-
patchDir,
-
extraMeta ? { },
unsupported ? false,
+
eolDate ? null,
}:
{
···
let
arch = if stdenv.hostPlatform.isx86_64 then "x86_64" else "generic";
+
+
versionUnderscored = builtins.replaceStrings [ "." ] [ "_" ] (
+
lib.versions.majorMinor kanidm.version
+
);
+
+
provisionPatches = [
+
(./. + "/provision-patches/${versionUnderscored}/oauth2-basic-secret-modify.patch")
+
(./. + "/provision-patches/${versionUnderscored}/recover-account.patch")
+
];
+
+
upgradeNote = ''
+
Please upgrade by verifying `kanidmd domain upgrade-check` and choosing the
+
next version with `services.kanidm.package = pkgs.kanidm_1_x;`
+
+
See upgrade guide at https://kanidm.github.io/kanidm/master/server_updates.html
+
'';
in
-
rustPlatform.buildRustPackage rec {
+
rustPlatform.buildRustPackage (finalAttrs: {
pname = "kanidm" + (lib.optionalString enableSecretProvisioning "-with-secret-provisioning");
inherit version cargoHash;
···
inherit hash;
};
-
KANIDM_BUILD_PROFILE = "release_nixpkgs_${arch}";
+
env.KANIDM_BUILD_PROFILE = "release_nixpkgs_${arch}";
-
patches = lib.optionals enableSecretProvisioning [
-
"${patchDir}/oauth2-basic-secret-modify.patch"
-
"${patchDir}/recover-account.patch"
-
];
+
patches = lib.optionals enableSecretProvisioning provisionPatches;
postPatch =
let
-
format = (formats.toml { }).generate "${KANIDM_BUILD_PROFILE}.toml";
+
format = (formats.toml { }).generate "${finalAttrs.env.KANIDM_BUILD_PROFILE}.toml";
socket_path = if stdenv.hostPlatform.isLinux then "/run/kanidmd/sock" else "/var/run/kanidm.socket";
profile = {
cpu_flags = if stdenv.hostPlatform.isx86_64 then "x86_64_legacy" else "none";
···
server_admin_bind_path = socket_path;
server_config_path = "/etc/kanidm/server.toml";
server_ui_pkg_path = "@htmx_ui_pkg_path@";
-
}
-
// lib.optionalAttrs (lib.versionOlder version "1.5") {
-
admin_bind_path = socket_path;
-
default_config_path = "/etc/kanidm/server.toml";
-
default_unix_shell_path = "${lib.getBin bashInteractive}/bin/bash";
-
htmx_ui_pkg_path = "@htmx_ui_pkg_path@";
-
}
-
// lib.optionalAttrs (lib.versions.majorMinor version == "1.3") {
-
web_ui_pkg_path = "@web_ui_pkg_path@";
};
in
''
-
cp ${format profile} libs/profiles/${KANIDM_BUILD_PROFILE}.toml
-
substituteInPlace libs/profiles/${KANIDM_BUILD_PROFILE}.toml --replace-fail '@htmx_ui_pkg_path@' "$out/ui/hpkg"
-
''
-
+ lib.optionalString (lib.versions.majorMinor version == "1.3") ''
-
substituteInPlace libs/profiles/${KANIDM_BUILD_PROFILE}.toml --replace-fail '@web_ui_pkg_path@' "$out/ui/pkg"
+
cp ${format profile} libs/profiles/${finalAttrs.env.KANIDM_BUILD_PROFILE}.toml
+
substituteInPlace libs/profiles/${finalAttrs.env.KANIDM_BUILD_PROFILE}.toml --replace-fail '@htmx_ui_pkg_path@' "$out/ui/hpkg"
'';
nativeBuildInputs = [
···
postBuild = ''
mkdir -p $out/ui
cp -r server/core/static $out/ui/hpkg
-
''
-
+ lib.optionalString (lib.versions.majorMinor version == "1.3") ''
-
cp -r server/web_ui/pkg $out/ui/pkg
'';
# Upstream runs with the Rust equivalent of -Werror,
···
passthru = {
tests = {
-
inherit (nixosTests) kanidm kanidm-provisioning;
+
kanidm = nixosTests.kanidm versionUnderscored;
+
kanidm-provisioning = nixosTests.kanidm-provisioning versionUnderscored;
};
updateScript = lib.optionals (!enableSecretProvisioning) (nix-update-script {
-
# avoid spurious releases and tags such as "debs"
extraArgs = [
"-vr"
-
"v([0-9\\.]*)"
+
"v(${lib.versions.major kanidm.version}\\.${lib.versions.minor kanidm.version}\\.[0-9]*)"
"--override-filename"
-
"pkgs/by-name/ka/kanidm/${
-
builtins.replaceStrings [ "." ] [ "_" ] (lib.versions.majorMinor kanidm.version)
-
}.nix"
+
"pkgs/by-name/ka/kanidm/${versionUnderscored}.nix"
];
});
inherit enableSecretProvisioning;
withSecretProvisioning = kanidm.override { enableSecretProvisioning = true; };
+
+
eolMessage = lib.optionalString (eolDate != null) ''
+
kanidm ${lib.versions.majorMinor version} is deprecated and will reach end-of-life on ${eolDate}
+
+
${upgradeNote}
+
'';
};
# can take over 4 hours on 2 cores and needs 16GB+ RAM
requiredSystemFeatures = [ "big-parallel" ];
-
meta =
-
with lib;
-
{
-
changelog = "https://github.com/kanidm/kanidm/releases/tag/v${version}";
-
description = "Simple, secure and fast identity management platform";
-
homepage = "https://github.com/kanidm/kanidm";
-
license = licenses.mpl20;
-
platforms = platforms.linux ++ platforms.darwin;
-
maintainers = with maintainers; [
-
adamcstephens
-
Flakebi
-
];
-
knownVulnerabilities = lib.optionals unsupported [
-
''
-
kanidm ${version} has reached EOL.
+
meta = {
+
changelog = "https://github.com/kanidm/kanidm/releases/tag/v${version}";
+
description = "Simple, secure and fast identity management platform";
+
homepage = "https://github.com/kanidm/kanidm";
+
license = lib.licenses.mpl20;
+
platforms = lib.platforms.linux ++ lib.platforms.darwin;
+
maintainers = with lib.maintainers; [
+
adamcstephens
+
Flakebi
+
];
+
knownVulnerabilities = lib.optionals unsupported [
+
''
+
kanidm ${lib.versions.majorMinor version} has reached end-of-life.
-
Please upgrade by verifying `kanidmd domain upgrade-check` and choosing the next version with `services.kanidm.package = pkgs.kanidm_1_x;`
-
See upgrade guide at https://kanidm.github.io/kanidm/master/server_updates.html
-
''
-
];
-
}
-
// extraMeta;
-
}
+
${upgradeNote}
+
''
+
];
+
};
+
})
pkgs/by-name/ka/kanidm/patches/1_5/oauth2-basic-secret-modify.patch pkgs/by-name/ka/kanidm/provision-patches/1_5/oauth2-basic-secret-modify.patch
pkgs/by-name/ka/kanidm/patches/1_5/recover-account.patch pkgs/by-name/ka/kanidm/provision-patches/1_5/recover-account.patch
pkgs/by-name/ka/kanidm/patches/1_6/oauth2-basic-secret-modify.patch pkgs/by-name/ka/kanidm/provision-patches/1_6/oauth2-basic-secret-modify.patch
pkgs/by-name/ka/kanidm/patches/1_6/recover-account.patch pkgs/by-name/ka/kanidm/provision-patches/1_6/recover-account.patch
+159
pkgs/by-name/ka/kanidm/provision-patches/1_7/oauth2-basic-secret-modify.patch
···
+
From fc26fe5ac9e9cd65af82609c5a4966c8f756ea0f Mon Sep 17 00:00:00 2001
+
From: oddlama <oddlama@oddlama.org>
+
Date: Fri, 21 Mar 2025 16:07:54 +0100
+
Subject: [PATCH 1/2] oauth2 basic secret modify
+
+
---
+
server/core/src/actors/v1_write.rs | 42 +++++++++++++++++++++++++++++
+
server/core/src/https/v1.rs | 6 ++++-
+
server/core/src/https/v1_oauth2.rs | 29 ++++++++++++++++++++
+
server/lib/src/server/migrations.rs | 16 +++++++++++
+
4 files changed, 92 insertions(+), 1 deletion(-)
+
+
diff --git a/server/core/src/actors/v1_write.rs b/server/core/src/actors/v1_write.rs
+
index 732e826c8..a2b8e503f 100644
+
--- a/server/core/src/actors/v1_write.rs
+
+++ b/server/core/src/actors/v1_write.rs
+
@@ -324,6 +324,48 @@ impl QueryServerWriteV1 {
+
.and_then(|_| idms_prox_write.commit().map(|_| ()))
+
}
+
+
+ #[instrument(
+
+ level = "info",
+
+ skip_all,
+
+ fields(uuid = ?eventid)
+
+ )]
+
+ pub async fn handle_oauth2_basic_secret_write(
+
+ &self,
+
+ client_auth_info: ClientAuthInfo,
+
+ filter: Filter<FilterInvalid>,
+
+ new_secret: String,
+
+ eventid: Uuid,
+
+ ) -> Result<(), OperationError> {
+
+ // Given a protoEntry, turn this into a modification set.
+
+ let ct = duration_from_epoch_now();
+
+ let mut idms_prox_write = self.idms.proxy_write(ct).await?;
+
+ let ident = idms_prox_write
+
+ .validate_client_auth_info_to_ident(client_auth_info, ct)
+
+ .map_err(|e| {
+
+ admin_error!(err = ?e, "Invalid identity");
+
+ e
+
+ })?;
+
+
+
+ let modlist = ModifyList::new_purge_and_set(
+
+ Attribute::OAuth2RsBasicSecret,
+
+ Value::SecretValue(new_secret),
+
+ );
+
+
+
+ let mdf =
+
+ ModifyEvent::from_internal_parts(ident, &modlist, &filter, &idms_prox_write.qs_write)
+
+ .map_err(|e| {
+
+ admin_error!(err = ?e, "Failed to begin modify during handle_oauth2_basic_secret_write");
+
+ e
+
+ })?;
+
+
+
+ trace!(?mdf, "Begin modify event");
+
+
+
+ idms_prox_write
+
+ .qs_write
+
+ .modify(&mdf)
+
+ .and_then(|_| idms_prox_write.commit())
+
+ }
+
+
+
#[instrument(
+
level = "info",
+
skip_all,
+
diff --git a/server/core/src/https/v1.rs b/server/core/src/https/v1.rs
+
index 30de387b8..a11aa8ecd 100644
+
--- a/server/core/src/https/v1.rs
+
+++ b/server/core/src/https/v1.rs
+
@@ -4,7 +4,7 @@ use axum::extract::{Path, State};
+
use axum::http::{HeaderMap, HeaderValue};
+
use axum::middleware::from_fn;
+
use axum::response::{IntoResponse, Response};
+
-use axum::routing::{delete, get, post, put};
+
+use axum::routing::{delete, get, post, put, patch};
+
use axum::{Extension, Json, Router};
+
use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite};
+
use compact_jwt::{Jwk, Jws, JwsSigner};
+
@@ -3129,6 +3129,10 @@ pub(crate) fn route_setup(state: ServerState) -> Router<ServerState> {
+
"/v1/oauth2/:rs_name/_basic_secret",
+
get(super::v1_oauth2::oauth2_id_get_basic_secret),
+
)
+
+ .route(
+
+ "/v1/oauth2/:rs_name/_basic_secret",
+
+ patch(super::v1_oauth2::oauth2_id_patch_basic_secret),
+
+ )
+
.route(
+
"/v1/oauth2/:rs_name/_scopemap/:group",
+
post(super::v1_oauth2::oauth2_id_scopemap_post)
+
diff --git a/server/core/src/https/v1_oauth2.rs b/server/core/src/https/v1_oauth2.rs
+
index f399539bc..ffad9921e 100644
+
--- a/server/core/src/https/v1_oauth2.rs
+
+++ b/server/core/src/https/v1_oauth2.rs
+
@@ -151,6 +151,35 @@ pub(crate) async fn oauth2_id_get_basic_secret(
+
.map_err(WebError::from)
+
}
+
+
+#[utoipa::path(
+
+ patch,
+
+ path = "/v1/oauth2/{rs_name}/_basic_secret",
+
+ request_body=ProtoEntry,
+
+ responses(
+
+ DefaultApiResponse,
+
+ ),
+
+ security(("token_jwt" = [])),
+
+ tag = "v1/oauth2",
+
+ operation_id = "oauth2_id_patch_basic_secret"
+
+)]
+
+/// Overwrite the basic secret for a given OAuth2 Resource Server.
+
+#[instrument(level = "info", skip(state, new_secret))]
+
+pub(crate) async fn oauth2_id_patch_basic_secret(
+
+ State(state): State<ServerState>,
+
+ Extension(kopid): Extension<KOpId>,
+
+ VerifiedClientInformation(client_auth_info): VerifiedClientInformation,
+
+ Path(rs_name): Path<String>,
+
+ Json(new_secret): Json<String>,
+
+) -> Result<Json<()>, WebError> {
+
+ let filter = oauth2_id(&rs_name);
+
+ state
+
+ .qe_w_ref
+
+ .handle_oauth2_basic_secret_write(client_auth_info, filter, new_secret, kopid.eventid)
+
+ .await
+
+ .map(Json::from)
+
+ .map_err(WebError::from)
+
+}
+
+
+
#[utoipa::path(
+
patch,
+
path = "/v1/oauth2/{rs_name}",
+
diff --git a/server/lib/src/server/migrations.rs b/server/lib/src/server/migrations.rs
+
index fd0bca8db..8621714f2 100644
+
--- a/server/lib/src/server/migrations.rs
+
+++ b/server/lib/src/server/migrations.rs
+
@@ -171,6 +171,22 @@ impl QueryServer {
+
reload_required = true;
+
};
+
+
+ // secret provisioning: allow idm_admin to modify OAuth2RsBasicSecret.
+
+ write_txn.internal_modify_uuid(
+
+ UUID_IDM_ACP_OAUTH2_MANAGE_V1,
+
+ &ModifyList::new_append(
+
+ Attribute::AcpCreateAttr,
+
+ Attribute::OAuth2RsBasicSecret.into(),
+
+ ),
+
+ )?;
+
+ write_txn.internal_modify_uuid(
+
+ UUID_IDM_ACP_OAUTH2_MANAGE_V1,
+
+ &ModifyList::new_append(
+
+ Attribute::AcpModifyPresentAttr,
+
+ Attribute::OAuth2RsBasicSecret.into(),
+
+ ),
+
+ )?;
+
+
+
// Execute whatever operations we have batched up and ready to go. This is needed
+
// to preserve ordering of the operations - if we reloaded after a remigrate then
+
// we would have skipped the patch level fix which needs to have occurred *first*.
+
--
+
2.49.0
+
+122
pkgs/by-name/ka/kanidm/provision-patches/1_7/recover-account.patch
···
+
From 229165abe5be596fc2be8e285884813a1b5a38c8 Mon Sep 17 00:00:00 2001
+
From: oddlama <oddlama@oddlama.org>
+
Date: Fri, 21 Mar 2025 16:08:15 +0100
+
Subject: [PATCH 2/2] recover account
+
+
---
+
server/core/src/actors/internal.rs | 5 +++--
+
server/core/src/admin.rs | 6 +++---
+
server/daemon/src/main.rs | 23 ++++++++++++++++++++++-
+
server/daemon/src/opt.rs | 7 +++++++
+
4 files changed, 35 insertions(+), 6 deletions(-)
+
+
diff --git a/server/core/src/actors/internal.rs b/server/core/src/actors/internal.rs
+
index 420e72c6c..e252bca51 100644
+
--- a/server/core/src/actors/internal.rs
+
+++ b/server/core/src/actors/internal.rs
+
@@ -172,17 +172,18 @@ impl QueryServerWriteV1 {
+
+
#[instrument(
+
level = "info",
+
- skip(self, eventid),
+
+ skip(self, password, eventid),
+
fields(uuid = ?eventid)
+
)]
+
pub(crate) async fn handle_admin_recover_account(
+
&self,
+
name: String,
+
+ password: Option<String>,
+
eventid: Uuid,
+
) -> Result<String, OperationError> {
+
let ct = duration_from_epoch_now();
+
let mut idms_prox_write = self.idms.proxy_write(ct).await?;
+
- let pw = idms_prox_write.recover_account(name.as_str(), None)?;
+
+ let pw = idms_prox_write.recover_account(name.as_str(), password.as_deref())?;
+
+
idms_prox_write.commit().map(|()| pw)
+
}
+
diff --git a/server/core/src/admin.rs b/server/core/src/admin.rs
+
index 90ccb1927..85e31ddef 100644
+
--- a/server/core/src/admin.rs
+
+++ b/server/core/src/admin.rs
+
@@ -24,7 +24,7 @@ pub use kanidm_proto::internal::{
+
+
#[derive(Serialize, Deserialize, Debug)]
+
pub enum AdminTaskRequest {
+
- RecoverAccount { name: String },
+
+ RecoverAccount { name: String, password: Option<String> },
+
ShowReplicationCertificate,
+
RenewReplicationCertificate,
+
RefreshReplicationConsumer,
+
@@ -309,8 +309,8 @@ async fn handle_client(
+
+
let resp = async {
+
match req {
+
- AdminTaskRequest::RecoverAccount { name } => {
+
- match server_rw.handle_admin_recover_account(name, eventid).await {
+
+ AdminTaskRequest::RecoverAccount { name, password } => {
+
+ match server_rw.handle_admin_recover_account(name, password, eventid).await {
+
Ok(password) => AdminTaskResponse::RecoverAccount { password },
+
Err(e) => {
+
error!(err = ?e, "error during recover-account");
+
diff --git a/server/daemon/src/main.rs b/server/daemon/src/main.rs
+
index c3b40faa0..2a57a307c 100644
+
--- a/server/daemon/src/main.rs
+
+++ b/server/daemon/src/main.rs
+
@@ -923,13 +923,34 @@ async fn kanidm_main(config: Configuration, opt: KanidmdParser) -> ExitCode {
+
.await;
+
}
+
}
+
- KanidmdOpt::RecoverAccount { name, commonopts } => {
+
+ KanidmdOpt::RecoverAccount { name, from_environment, commonopts } => {
+
info!("Running account recovery ...");
+
let output_mode: ConsoleOutputMode = commonopts.output_mode.to_owned().into();
+
+ let password = if *from_environment {
+
+ match std::env::var("KANIDM_RECOVER_ACCOUNT_PASSWORD_FILE") {
+
+ Ok(path) => match tokio::fs::read_to_string(&path).await {
+
+ Ok(contents) => Some(contents),
+
+ Err(e) => {
+
+ error!("Failed to read password file '{}': {}", path, e);
+
+ return ExitCode::FAILURE;
+
+ }
+
+ },
+
+ Err(_) => match std::env::var("KANIDM_RECOVER_ACCOUNT_PASSWORD") {
+
+ Ok(val) => Some(val),
+
+ Err(_) => {
+
+ error!("Neither KANIDM_RECOVER_ACCOUNT_PASSWORD_FILE nor KANIDM_RECOVER_ACCOUNT_PASSWORD was set");
+
+ return ExitCode::FAILURE;
+
+ }
+
+ }
+
+ }
+
+ } else {
+
+ None
+
+ };
+
submit_admin_req(
+
config.adminbindpath.as_str(),
+
AdminTaskRequest::RecoverAccount {
+
name: name.to_owned(),
+
+ password,
+
},
+
output_mode,
+
)
+
diff --git a/server/daemon/src/opt.rs b/server/daemon/src/opt.rs
+
index f1b45a5b3..ca19fb6a5 100644
+
--- a/server/daemon/src/opt.rs
+
+++ b/server/daemon/src/opt.rs
+
@@ -236,6 +236,13 @@ enum KanidmdOpt {
+
#[clap(value_parser)]
+
/// The account name to recover credentials for.
+
name: String,
+
+ /// Use a password given via an environment variable.
+
+ /// - `KANIDM_RECOVER_ACCOUNT_PASSWORD_FILE` takes precedence and reads the desired
+
+ /// password from the given file
+
+ /// - `KANIDM_RECOVER_ACCOUNT_PASSWORD` directly takes a
+
+ /// password - beware that this will leave the password in the environment
+
+ #[clap(long = "from-environment")]
+
+ from_environment: bool,
+
#[clap(flatten)]
+
commonopts: CommonOpt,
+
},
+
--
+
2.49.0
+
+5
pkgs/top-level/all-packages.nix
···
kanidm_1_5 = callPackage ../by-name/ka/kanidm/1_5.nix { kanidm = kanidm_1_5; };
kanidm_1_6 = callPackage ../by-name/ka/kanidm/1_6.nix { kanidm = kanidm_1_6; };
+
kanidm_1_7 = callPackage ../by-name/ka/kanidm/1_7.nix { kanidm = kanidm_1_7; };
kanidmWithSecretProvisioning = kanidmWithSecretProvisioning_1_6;
···
kanidmWithSecretProvisioning_1_6 = callPackage ../by-name/ka/kanidm/1_6.nix {
+
enableSecretProvisioning = true;
+
};
+
+
kanidmWithSecretProvisioning_1_7 = callPackage ../by-name/ka/kanidm/1_7.nix {
enableSecretProvisioning = true;