mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-06-05 21:03:40 +00:00
kanidm_1_10: init at 1.10.0
Changelog: https://github.com/kanidm/kanidm/releases/tag/v1.10.0
This commit is contained in:
@@ -18,7 +18,7 @@ in
|
||||
name = "kanidm-provisioning-${kanidmPackage.version}";
|
||||
meta.maintainers = with pkgs.lib.maintainers; [ oddlama ];
|
||||
|
||||
_module.args.kanidmPackage = pkgs.lib.mkDefault pkgs.kanidmWithSecretProvisioning_1_8;
|
||||
_module.args.kanidmPackage = pkgs.lib.mkDefault pkgs.kanidmWithSecretProvisioning_1_10;
|
||||
|
||||
nodes.provision =
|
||||
{ pkgs, lib, ... }:
|
||||
|
||||
@@ -22,7 +22,7 @@ in
|
||||
oddlama
|
||||
];
|
||||
|
||||
_module.args.kanidmPackage = pkgs.lib.mkDefault pkgs.kanidm_1_8;
|
||||
_module.args.kanidmPackage = pkgs.lib.mkDefault pkgs.kanidm_1_10;
|
||||
|
||||
nodes.server =
|
||||
{ pkgs, ... }:
|
||||
|
||||
5
pkgs/servers/kanidm/1_10.nix
Normal file
5
pkgs/servers/kanidm/1_10.nix
Normal file
@@ -0,0 +1,5 @@
|
||||
import ./generic.nix {
|
||||
version = "1.10.0";
|
||||
hash = "sha256-VKzeyhps9NC+tU7NaGZf2kTCCK6J5LU1ewJBhS/Noek=";
|
||||
cargoHash = "sha256-hvWZLGJBsMbpZQixafdYzqT+zMbk2vAtPYpJ4OBVhoU=";
|
||||
}
|
||||
@@ -2,4 +2,5 @@ import ./generic.nix {
|
||||
version = "1.9.3";
|
||||
hash = "sha256-YI2nShQhsCd1vn7S4VeCELfcU0HsmZrFs60kllJJFAo=";
|
||||
cargoHash = "sha256-b6kBDA/CDJHbybfvbRRZ++q9H+SVRu0BmgkwzN2i/YU=";
|
||||
eolDate = "2026-05-31";
|
||||
}
|
||||
|
||||
@@ -59,6 +59,8 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
inherit hash;
|
||||
};
|
||||
|
||||
__structuredAttrs = true;
|
||||
|
||||
env.KANIDM_BUILD_PROFILE = "release_nixpkgs_${arch}";
|
||||
|
||||
patches =
|
||||
@@ -105,13 +107,15 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
openssl
|
||||
sqlite
|
||||
pam
|
||||
rust-jemalloc-sys
|
||||
]
|
||||
++ lib.optionals stdenv.hostPlatform.isLinux [
|
||||
udev
|
||||
]
|
||||
++ lib.optionals (lib.versionOlder finalAttrs.version "1.10") [
|
||||
openssl
|
||||
];
|
||||
|
||||
# The UI needs to be in place before the tests are run.
|
||||
@@ -133,6 +137,9 @@ rustPlatform.buildRustPackage (finalAttrs: {
|
||||
''profile.release.lto="off"''
|
||||
];
|
||||
|
||||
# A bunch of the tests break due to the sandboxing.
|
||||
doCheck = false;
|
||||
|
||||
preFixup = ''
|
||||
installShellCompletion \
|
||||
--bash $releaseDir/build/completions/*.bash \
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
From 5b97267c49def10f5a4b7bb372963261c0f4b08d Mon Sep 17 00:00:00 2001
|
||||
From: oddlama <oddlama@oddlama.org>
|
||||
Date: Fri, 1 May 2026 15:01:05 +0200
|
||||
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 977292ae9..bf79c42a1 100644
|
||||
--- a/server/core/src/actors/v1_write.rs
|
||||
+++ b/server/core/src/actors/v1_write.rs
|
||||
@@ -326,6 +326,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 ba3ea2827..489ce0002 100644
|
||||
--- a/server/core/src/https/v1.rs
|
||||
+++ b/server/core/src/https/v1.rs
|
||||
@@ -10,7 +10,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};
|
||||
@@ -3156,6 +3156,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 fdc3647b4..ed4709d27 100644
|
||||
--- a/server/core/src/https/v1_oauth2.rs
|
||||
+++ b/server/core/src/https/v1_oauth2.rs
|
||||
@@ -149,6 +149,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 b3effb95b..5c6a56d24 100644
|
||||
--- a/server/lib/src/server/migrations.rs
|
||||
+++ b/server/lib/src/server/migrations.rs
|
||||
@@ -220,6 +220,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.53.0
|
||||
|
||||
128
pkgs/servers/kanidm/provision-patches/1_10/recover-account.patch
Normal file
128
pkgs/servers/kanidm/provision-patches/1_10/recover-account.patch
Normal file
@@ -0,0 +1,128 @@
|
||||
From e8cd69afcee9d8d37233fa998cf9d1fa124ae90d Mon Sep 17 00:00:00 2001
|
||||
From: oddlama <oddlama@oddlama.org>
|
||||
Date: Fri, 1 May 2026 15:01:14 +0200
|
||||
Subject: [PATCH 2/2] recover account
|
||||
|
||||
---
|
||||
server/core/src/actors/internal.rs | 5 +++--
|
||||
server/core/src/admin.rs | 6 +++---
|
||||
server/daemon/src/main.rs | 24 +++++++++++++++++++++++-
|
||||
server/daemon/src/opt.rs | 7 +++++++
|
||||
4 files changed, 36 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/server/core/src/actors/internal.rs b/server/core/src/actors/internal.rs
|
||||
index deed7350d..f4e9e486a 100644
|
||||
--- a/server/core/src/actors/internal.rs
|
||||
+++ b/server/core/src/actors/internal.rs
|
||||
@@ -189,17 +189,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 6a13dcaab..6b1070113 100644
|
||||
--- a/server/core/src/admin.rs
|
||||
+++ b/server/core/src/admin.rs
|
||||
@@ -27,7 +27,7 @@ const REPL_CTRL_TIMEOUT: Duration = Duration::from_secs(15);
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub enum AdminTaskRequest {
|
||||
- RecoverAccount { name: String },
|
||||
+ RecoverAccount { name: String, password: Option<String> },
|
||||
DisableAccount { name: String },
|
||||
ShowReplicationCertificate,
|
||||
ShowReplicationCertificateMetadata,
|
||||
@@ -416,8 +416,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 13653a5cb..ae560f9ce 100644
|
||||
--- a/server/daemon/src/main.rs
|
||||
+++ b/server/daemon/src/main.rs
|
||||
@@ -380,11 +380,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),
|
||||
+ 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_json(
|
||||
config.adminbindpath.as_str(),
|
||||
AdminTaskRequest::RecoverAccount {
|
||||
name: name.to_owned(),
|
||||
+ password,
|
||||
},
|
||||
)
|
||||
.await;
|
||||
@@ -1008,6 +1029,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 524ba3134..fa3d70f44 100644
|
||||
--- a/server/daemon/src/opt.rs
|
||||
+++ b/server/daemon/src/opt.rs
|
||||
@@ -128,6 +128,13 @@ enum ScriptingCommand {
|
||||
#[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,
|
||||
},
|
||||
/// Backup
|
||||
Backup {
|
||||
--
|
||||
2.53.0
|
||||
|
||||
@@ -7976,14 +7976,20 @@ with pkgs;
|
||||
kanidm_1_9 = callPackage ../servers/kanidm/1_9.nix {
|
||||
kanidmWithSecretProvisioning = kanidmWithSecretProvisioning_1_9;
|
||||
};
|
||||
kanidm_1_10 = callPackage ../servers/kanidm/1_10.nix {
|
||||
kanidmWithSecretProvisioning = kanidmWithSecretProvisioning_1_10;
|
||||
};
|
||||
|
||||
kanidmWithSecretProvisioning_1_8 = kanidm_1_8.override { enableSecretProvisioning = true; };
|
||||
kanidmWithSecretProvisioning_1_9 = kanidm_1_9.override { enableSecretProvisioning = true; };
|
||||
kanidmWithSecretProvisioning_1_10 = kanidm_1_10.override { enableSecretProvisioning = true; };
|
||||
})
|
||||
kanidm_1_8
|
||||
kanidm_1_9
|
||||
kanidm_1_10
|
||||
kanidmWithSecretProvisioning_1_8
|
||||
kanidmWithSecretProvisioning_1_9
|
||||
kanidmWithSecretProvisioning_1_10
|
||||
;
|
||||
|
||||
lemmy-server = callPackage ../servers/web-apps/lemmy/server.nix { };
|
||||
|
||||
Reference in New Issue
Block a user