diff --git a/nixos/modules/services/security/kanidm.nix b/nixos/modules/services/security/kanidm.nix index ed904d888d03..47e9fd80e59a 100644 --- a/nixos/modules/services/security/kanidm.nix +++ b/nixos/modules/services/security/kanidm.nix @@ -39,6 +39,7 @@ let subtractLists types unique + versionAtLeast ; cfg = config.services.kanidm; @@ -142,12 +143,14 @@ let builtins.toJSON { inherit (cfg.provision) groups persons systems; } ); + scriptingArg = optionalString (versionAtLeast cfg.package.version "1.9") "scripting"; + # Only recover the admin account if a password should explicitly be provisioned # for the account. Otherwise it is not needed for provisioning. maybeRecoverAdmin = optionalString (cfg.provision.adminPasswordFile != null) '' KANIDM_ADMIN_PASSWORD=$(< ${cfg.provision.adminPasswordFile}) # We always reset the admin account password if a desired password was specified. - if ! KANIDM_RECOVER_ACCOUNT_PASSWORD=$KANIDM_ADMIN_PASSWORD ${cfg.package}/bin/kanidmd recover-account -c ${serverConfigFile} admin --from-environment >/dev/null; then + if ! KANIDM_RECOVER_ACCOUNT_PASSWORD=$KANIDM_ADMIN_PASSWORD ${cfg.package}/bin/kanidmd ${scriptingArg} recover-account -c ${serverConfigFile} admin --from-environment >/dev/null; then echo "Failed to recover admin account" >&2 exit 1 fi @@ -161,19 +164,35 @@ let '' KANIDM_IDM_ADMIN_PASSWORD=$(< ${cfg.provision.idmAdminPasswordFile}) # We always reset the idm_admin account password if a desired password was specified. - if ! KANIDM_RECOVER_ACCOUNT_PASSWORD=$KANIDM_IDM_ADMIN_PASSWORD ${cfg.package}/bin/kanidmd recover-account -c ${serverConfigFile} idm_admin --from-environment >/dev/null; then + if ! KANIDM_RECOVER_ACCOUNT_PASSWORD=$KANIDM_IDM_ADMIN_PASSWORD ${cfg.package}/bin/kanidmd ${scriptingArg} recover-account -c ${serverConfigFile} idm_admin --from-environment >/dev/null; then echo "Failed to recover idm_admin account" >&2 exit 1 fi '' + else if versionAtLeast cfg.package.version "1.9" then + '' + # Recover idm_admin account + if ! recover_out=$(${cfg.package}/bin/kanidmd scripting recover-account -c ${serverConfigFile} idm_admin); then + echo "$recover_out" >&2 + echo "kanidm provision: Failed to recover idm_admin account" >&2 + exit 1 + fi + + if ! KANIDM_IDM_ADMIN_PASSWORD=$(${getExe pkgs.jq} -r .output <<< "$recover_out"); then + echo "$recover_out" >&2 + echo "kanidm provision: Failed to parse password for idm_admin account" >&2 + exit 1 + fi + '' else '' # Recover idm_admin account if ! recover_out=$(${cfg.package}/bin/kanidmd recover-account -c ${serverConfigFile} idm_admin -o json); then echo "$recover_out" >&2 - echo "kanidm provision: Failed to recover admin account" >&2 + echo "kanidm provision: Failed to recover idm_admin account" >&2 exit 1 fi + if ! KANIDM_IDM_ADMIN_PASSWORD=$(grep '{"password' <<< "$recover_out" | ${getExe pkgs.jq} -r .password); then echo "$recover_out" >&2 echo "kanidm provision: Failed to parse password for idm_admin account" >&2 diff --git a/pkgs/servers/kanidm/provision-patches/1_9/oauth2-basic-secret-modify.patch b/pkgs/servers/kanidm/provision-patches/1_9/oauth2-basic-secret-modify.patch index c6ba31323669..e109bedcce0a 100644 --- a/pkgs/servers/kanidm/provision-patches/1_9/oauth2-basic-secret-modify.patch +++ b/pkgs/servers/kanidm/provision-patches/1_9/oauth2-basic-secret-modify.patch @@ -1,6 +1,6 @@ -From bebd0ae51344eba2bc9bb8e8bd88f279daf09581 Mon Sep 17 00:00:00 2001 +From 3ba8714f99d57e1434aeed316f6fd9cd115198dc Mon Sep 17 00:00:00 2001 From: oddlama -Date: Mon, 10 Nov 2025 19:58:39 +0100 +Date: Sat, 14 Feb 2026 12:23:49 +0100 Subject: [PATCH 1/2] oauth2 basic secret modify --- @@ -11,7 +11,7 @@ Subject: [PATCH 1/2] oauth2 basic secret modify 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 +index 47be2002e..4e3522e1a 100644 --- a/server/core/src/actors/v1_write.rs +++ b/server/core/src/actors/v1_write.rs @@ -324,6 +324,48 @@ impl QueryServerWriteV1 { @@ -64,7 +64,7 @@ index 732e826c8..a2b8e503f 100644 level = "info", skip_all, diff --git a/server/core/src/https/v1.rs b/server/core/src/https/v1.rs -index 7d5beb1f0..210147e0a 100644 +index 97be6d666..33778ae08 100644 --- a/server/core/src/https/v1.rs +++ b/server/core/src/https/v1.rs @@ -10,7 +10,7 @@ use axum::extract::{Path, State}; @@ -76,7 +76,7 @@ index 7d5beb1f0..210147e0a 100644 use axum::{Extension, Json, Router}; use axum_extra::extract::cookie::{Cookie, CookieJar, SameSite}; use compact_jwt::{Jwk, Jws, JwsSigner}; -@@ -3113,6 +3113,10 @@ pub(crate) fn route_setup(state: ServerState) -> Router { +@@ -3123,6 +3123,10 @@ pub(crate) fn route_setup(state: ServerState) -> Router { "/v1/oauth2/{rs_name}/_basic_secret", get(super::v1_oauth2::oauth2_id_get_basic_secret), ) @@ -88,7 +88,7 @@ index 7d5beb1f0..210147e0a 100644 "/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 +index c6209c750..16dd3e348 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( @@ -128,10 +128,10 @@ index f399539bc..ffad9921e 100644 patch, path = "/v1/oauth2/{rs_name}", diff --git a/server/lib/src/server/migrations.rs b/server/lib/src/server/migrations.rs -index a916eced2..94327e938 100644 +index e5dcdfc04..add51fba5 100644 --- a/server/lib/src/server/migrations.rs +++ b/server/lib/src/server/migrations.rs -@@ -172,6 +172,22 @@ impl QueryServer { +@@ -220,6 +220,22 @@ impl QueryServer { reload_required = true; }; @@ -155,5 +155,5 @@ index a916eced2..94327e938 100644 // 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.51.0 +2.52.0 diff --git a/pkgs/servers/kanidm/provision-patches/1_9/recover-account.patch b/pkgs/servers/kanidm/provision-patches/1_9/recover-account.patch index 0757b4fbb5d6..25f73d8e2492 100644 --- a/pkgs/servers/kanidm/provision-patches/1_9/recover-account.patch +++ b/pkgs/servers/kanidm/provision-patches/1_9/recover-account.patch @@ -1,20 +1,20 @@ -From 29dab03201185675d116dd5da6928c6ca3ad30ff Mon Sep 17 00:00:00 2001 +From 8db3febfce8057011156e80a371c4312a79be4cc Mon Sep 17 00:00:00 2001 From: oddlama -Date: Mon, 10 Nov 2025 20:01:07 +0100 +Date: Sat, 14 Feb 2026 12:27:00 +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/main.rs | 24 +++++++++++++++++++++++- server/daemon/src/opt.rs | 7 +++++++ - 4 files changed, 35 insertions(+), 6 deletions(-) + 4 files changed, 36 insertions(+), 6 deletions(-) diff --git a/server/core/src/actors/internal.rs b/server/core/src/actors/internal.rs -index b3708f36d..6a52735fc 100644 +index abcc1b27c..2a63d0e9d 100644 --- a/server/core/src/actors/internal.rs +++ b/server/core/src/actors/internal.rs -@@ -186,17 +186,18 @@ impl QueryServerWriteV1 { +@@ -189,17 +189,18 @@ impl QueryServerWriteV1 { #[instrument( level = "info", @@ -36,10 +36,10 @@ index b3708f36d..6a52735fc 100644 idms_prox_write.commit().map(|()| pw) } diff --git a/server/core/src/admin.rs b/server/core/src/admin.rs -index b74cc90c5..660e3de8f 100644 +index e00eb0476..175a6f661 100644 --- a/server/core/src/admin.rs +++ b/server/core/src/admin.rs -@@ -24,7 +24,7 @@ pub use kanidm_proto::internal::{ +@@ -23,7 +23,7 @@ pub use kanidm_proto::internal::{ #[derive(Serialize, Deserialize, Debug)] pub enum AdminTaskRequest { @@ -48,7 +48,7 @@ index b74cc90c5..660e3de8f 100644 DisableAccount { name: String }, ShowReplicationCertificate, RenewReplicationCertificate, -@@ -334,8 +334,8 @@ async fn handle_client( +@@ -341,8 +341,8 @@ async fn handle_client( let resp = async { match req { @@ -60,18 +60,16 @@ index b74cc90c5..660e3de8f 100644 Err(e) => { error!(err = ?e, "error during recover-account"); diff --git a/server/daemon/src/main.rs b/server/daemon/src/main.rs -index 2ad7830cc..52fa8d2d9 100644 +index 611022a63..0b2f863e4 100644 --- a/server/daemon/src/main.rs +++ b/server/daemon/src/main.rs -@@ -832,13 +832,34 @@ async fn kanidm_main(config: Configuration, opt: KanidmdParser) -> ExitCode { - .await; - } - } -- KanidmdOpt::RecoverAccount { name } => { -+ KanidmdOpt::RecoverAccount { name, from_environment } => { - info!("Running account recovery ..."); - let output_mode: ConsoleOutputMode = opt.output_mode.into(); -+ let password = if *from_environment { +@@ -370,11 +370,32 @@ fn check_file_ownership(opt: &KanidmdParser) -> Result<(), ExitCode> { + + async fn scripting_command(cmd: ScriptingCommand, config: Configuration) -> ExitCode { + match cmd { +- ScriptingCommand::RecoverAccount { name } => { ++ ScriptingCommand::RecoverAccount { name, from_environment } => { ++ 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), @@ -91,19 +89,27 @@ index 2ad7830cc..52fa8d2d9 100644 + } else { + None + }; - submit_admin_req( + submit_admin_req_json( config.adminbindpath.as_str(), AdminTaskRequest::RecoverAccount { name: name.to_owned(), + password, }, - output_mode, ) + .await; +@@ -998,6 +1019,7 @@ async fn kanidm_main(config: Configuration, opt: KanidmdParser) -> ExitCode { + config.adminbindpath.as_str(), + AdminTaskRequest::RecoverAccount { + name: name.to_owned(), ++ password: None, + }, + ) + .await; diff --git a/server/daemon/src/opt.rs b/server/daemon/src/opt.rs -index 05c5b9fb3..834b8f9cf 100644 +index ba5d00fc7..f1497f6dc 100644 --- a/server/daemon/src/opt.rs +++ b/server/daemon/src/opt.rs -@@ -158,6 +158,13 @@ enum KanidmdOpt { +@@ -128,6 +128,13 @@ enum ScriptingCommand { #[clap(value_parser)] /// The account name to recover credentials for. name: String, @@ -115,8 +121,8 @@ index 05c5b9fb3..834b8f9cf 100644 + #[clap(long = "from-environment")] + from_environment: bool, }, - #[clap(name = "disable-account")] - /// Disable an account so that it can not be used. This can be reset with `recover-account`. + /// Backup + Backup { -- -2.51.0 +2.52.0 diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index dc03f500abe3..deef464f2aca 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -8290,7 +8290,7 @@ with pkgs; kanidmWithSecretProvisioning = kanidmWithSecretProvisioning_1_8; }; kanidm_1_9 = callPackage ../servers/kanidm/1_9.nix { - kanidmWithSecretProvisioning = kanidmWithSecretProvisioning_1_8; + kanidmWithSecretProvisioning = kanidmWithSecretProvisioning_1_9; }; kanidmWithSecretProvisioning_1_7 = kanidm_1_7.override { enableSecretProvisioning = true; };