From: Samuel Rufinatscha <s.rufinatscha@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [PATCH proxmox v8 6/6] token shadow: deduplicate more code into apply_api_mutation
Date: Thu, 9 Apr 2026 17:54:26 +0200 [thread overview]
Message-ID: <20260409155437.312760-7-s.rufinatscha@proxmox.com> (raw)
In-Reply-To: <20260409155437.312760-1-s.rufinatscha@proxmox.com>
Signed-off-by: Samuel Rufinatscha <s.rufinatscha@proxmox.com>
---
proxmox-access-control/src/token_shadow.rs | 71 +++++++++-------------
1 file changed, 29 insertions(+), 42 deletions(-)
diff --git a/proxmox-access-control/src/token_shadow.rs b/proxmox-access-control/src/token_shadow.rs
index 270f3bfa..a8cd4209 100644
--- a/proxmox-access-control/src/token_shadow.rs
+++ b/proxmox-access-control/src/token_shadow.rs
@@ -164,43 +164,13 @@ pub fn verify_secret(tokenid: &Authid, secret: &str) -> Result<(), Error> {
/// Generates a new secret for the given tokenid / API token, sets it then returns it.
/// The secret is stored as salted hash.
pub fn generate_and_set_secret(tokenid: &Authid) -> Result<String, Error> {
- let secret = format!("{:x}", proxmox_uuid::Uuid::generate());
-
- if !tokenid.is_token() {
- bail!("not an API token ID");
- }
-
- let guard = lock_config()?;
-
- // Capture state before we write to detect external edits.
- let pre_meta = shadow_mtime_len().unwrap_or((None, None));
-
- let mut data = read_file()?;
- let hashed_secret = proxmox_sys::crypt::encrypt_pw(&secret)?;
- data.insert(tokenid.clone(), hashed_secret);
- write_file(data)?;
-
- apply_api_mutation(guard, tokenid, Some(&secret), pre_meta);
-
- Ok(secret)
+ apply_api_mutation(tokenid, true)?
+ .ok_or_else(|| format_err!("Failed to generate API token secret"))
}
/// Deletes the entry for the given tokenid.
pub fn delete_secret(tokenid: &Authid) -> Result<(), Error> {
- if !tokenid.is_token() {
- bail!("not an API token ID");
- }
-
- let guard = lock_config()?;
-
- // Capture state before we write to detect external edits.
- let pre_meta = shadow_mtime_len().unwrap_or((None, None));
-
- let mut data = read_file()?;
- data.remove(tokenid);
- write_file(data)?;
-
- apply_api_mutation(guard, tokenid, None, pre_meta);
+ apply_api_mutation(tokenid, false)?;
Ok(())
}
@@ -293,12 +263,28 @@ fn cache_try_insert_secret(tokenid: Authid, secret: String, gen_before: usize) {
}
}
-fn apply_api_mutation(
- _guard: ApiLockGuard,
- tokenid: &Authid,
- secret: Option<&str>,
- pre_write_meta: (Option<SystemTime>, Option<u64>),
-) {
+fn apply_api_mutation(tokenid: &Authid, generate: bool) -> Result<Option<String>, Error> {
+ if !tokenid.is_token() {
+ bail!("not an API token ID");
+ }
+
+ let _guard = lock_config()?;
+
+ // Capture state before we write to detect external edits.
+ let pre_write_meta = shadow_mtime_len().unwrap_or((None, None));
+
+ let mut data = read_file()?;
+ let secret = if generate {
+ let secret = format!("{:x}", proxmox_uuid::Uuid::generate());
+ let hashed_secret = proxmox_sys::crypt::encrypt_pw(&secret)?;
+ data.insert(tokenid.clone(), hashed_secret);
+ Some(secret)
+ } else {
+ data.remove(tokenid);
+ None
+ };
+ write_file(data)?;
+
let now = epoch_i64();
// Signal cache invalidation to other processes (best-effort).
@@ -308,14 +294,14 @@ fn apply_api_mutation(
// If we cannot get the current generation, we cannot trust the cache
let Some(current_gen) = token_shadow_generation() else {
cache.reset_and_set_gen(0);
- return;
+ return Ok(secret);
};
// If we cannot bump the generation, or if it changed after
// obtaining the cache write lock, we cannot trust the cache
if bumped_gen != Some(current_gen) {
cache.reset_and_set_gen(current_gen);
- return;
+ return Ok(secret);
}
// If our cached file metadata does not match the on-disk state before our write,
@@ -329,7 +315,7 @@ fn apply_api_mutation(
}
// Apply the new mutation.
- match secret {
+ match &secret {
Some(secret) => {
let cached_secret = CachedSecret {
secret: secret.to_owned(),
@@ -354,6 +340,7 @@ fn apply_api_mutation(
cache.reset_and_set_gen(current_gen);
}
}
+ Ok(secret)
}
/// Get the current generation.
--
2.47.3
next prev parent reply other threads:[~2026-04-09 15:54 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-09 15:54 [PATCH proxmox{,-datacenter-manager} v8 0/9] token-shadow: reduce api token verification overhead Samuel Rufinatscha
2026-04-09 15:54 ` [PATCH proxmox v8 1/6] token shadow: split AccessControlConfig and add token.shadow generation Samuel Rufinatscha
2026-04-09 15:54 ` [PATCH proxmox v8 2/6] token shadow: cache verified API token secrets Samuel Rufinatscha
2026-04-09 15:54 ` [PATCH proxmox v8 3/6] token shadow: invalidate token-secret cache on token.shadow changes Samuel Rufinatscha
2026-04-09 15:54 ` [PATCH proxmox v8 4/6] token shadow: add TTL window to token secret cache Samuel Rufinatscha
2026-04-09 15:54 ` [PATCH proxmox v8 5/6] token shadow: inline set_secret fn Samuel Rufinatscha
2026-04-09 15:54 ` Samuel Rufinatscha [this message]
2026-04-09 15:54 ` [PATCH proxmox-datacenter-manager v8 1/3] pdm-config: implement access control backend hooks Samuel Rufinatscha
2026-04-09 15:54 ` [PATCH proxmox-datacenter-manager v8 2/3] pdm-config: wire user and ACL cache generation Samuel Rufinatscha
2026-04-09 15:54 ` [PATCH proxmox-datacenter-manager v8 3/3] pdm-config: wire token.shadow generation Samuel Rufinatscha
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260409155437.312760-7-s.rufinatscha@proxmox.com \
--to=s.rufinatscha@proxmox.com \
--cc=pbs-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.