From: Shannon Sterz <s.sterz@proxmox.com>
To: pbs-devel@lists.proxmox.com
Subject: [pbs-devel] [PATCH proxmox v3 3/7] access-control: make token shadow implementation re-usable
Date: Wed, 19 Jun 2024 11:54:14 +0200 [thread overview]
Message-ID: <20240619095418.126368-4-s.sterz@proxmox.com> (raw)
In-Reply-To: <20240619095418.126368-1-s.sterz@proxmox.com>
this commit factors out the token shadow implementation from
`proxmox-backup` so it can be used in other products.
Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
proxmox-access-control/Cargo.toml | 2 +
proxmox-access-control/src/init.rs | 7 ++
proxmox-access-control/src/lib.rs | 1 +
proxmox-access-control/src/token_shadow.rs | 84 ++++++++++++++++++++++
4 files changed, 94 insertions(+)
create mode 100644 proxmox-access-control/src/token_shadow.rs
diff --git a/proxmox-access-control/Cargo.toml b/proxmox-access-control/Cargo.toml
index 68cbf460..01ab5f5a 100644
--- a/proxmox-access-control/Cargo.toml
+++ b/proxmox-access-control/Cargo.toml
@@ -17,9 +17,11 @@ anyhow.workspace = true
nix.workspace = true
openssl.workspace = true
serde.workspace = true
+serde_json.workspace = true
# proxmox-notify.workspace = true
proxmox-auth-api = { workspace = true, features = [ "api-types" ] }
proxmox-schema.workspace = true
proxmox-product-config.workspace = true
+proxmox-sys = { workspace = true, features = [ "crypt" ] }
proxmox-time.workspace = true
diff --git a/proxmox-access-control/src/init.rs b/proxmox-access-control/src/init.rs
index a8dfa24e..2f5593ea 100644
--- a/proxmox-access-control/src/init.rs
+++ b/proxmox-access-control/src/init.rs
@@ -72,3 +72,10 @@ pub(crate) fn acl_config_lock() -> PathBuf {
conf_dir().join(".acl.lck")
}
+pub(crate) fn token_shadow() -> PathBuf {
+ conf_dir().join("token.shadow")
+}
+
+pub(crate) fn token_shadow_lock() -> PathBuf {
+ conf_dir().join("token.shadow.lock")
+}
diff --git a/proxmox-access-control/src/lib.rs b/proxmox-access-control/src/lib.rs
index edb42568..524b0e60 100644
--- a/proxmox-access-control/src/lib.rs
+++ b/proxmox-access-control/src/lib.rs
@@ -1,3 +1,4 @@
pub mod acl;
pub mod init;
+pub mod token_shadow;
pub mod types;
diff --git a/proxmox-access-control/src/token_shadow.rs b/proxmox-access-control/src/token_shadow.rs
new file mode 100644
index 00000000..ab8925b7
--- /dev/null
+++ b/proxmox-access-control/src/token_shadow.rs
@@ -0,0 +1,84 @@
+use std::collections::HashMap;
+
+use anyhow::{bail, format_err, Error};
+use proxmox_product_config::{open_api_lockfile, replace_config, ApiLockGuard};
+use serde::{Deserialize, Serialize};
+use serde_json::{from_value, Value};
+
+use proxmox_auth_api::types::Authid;
+
+use crate::init::{token_shadow, token_shadow_lock};
+
+#[derive(Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+/// ApiToken id / secret pair
+pub struct ApiTokenSecret {
+ pub tokenid: Authid,
+ pub secret: String,
+}
+
+// Get exclusive lock
+fn lock_config() -> Result<ApiLockGuard, Error> {
+ open_api_lockfile(token_shadow_lock(), None, true)
+}
+
+fn read_file() -> Result<HashMap<Authid, String>, Error> {
+ let json = proxmox_sys::fs::file_get_json(token_shadow(), Some(Value::Null))?;
+
+ if json == Value::Null {
+ Ok(HashMap::new())
+ } else {
+ // swallow serde error which might contain sensitive data
+ from_value(json)
+ .map_err(|_err| format_err!("unable to parse '{}'", token_shadow().display()))
+ }
+}
+
+fn write_file(data: HashMap<Authid, String>) -> Result<(), Error> {
+ let json = serde_json::to_vec(&data)?;
+ replace_config(token_shadow(), &json)
+}
+
+/// Verifies that an entry for given tokenid / API token secret exists
+pub fn verify_secret(tokenid: &Authid, secret: &str) -> Result<(), Error> {
+ if !tokenid.is_token() {
+ bail!("not an API token ID");
+ }
+
+ let data = read_file()?;
+ match data.get(tokenid) {
+ Some(hashed_secret) => proxmox_sys::crypt::verify_crypt_pw(secret, hashed_secret),
+ None => bail!("invalid API token"),
+ }
+}
+
+/// Adds a new entry for the given tokenid / API token secret. The secret is stored as salted hash.
+pub fn set_secret(tokenid: &Authid, secret: &str) -> Result<(), Error> {
+ if !tokenid.is_token() {
+ bail!("not an API token ID");
+ }
+
+ let _guard = lock_config()?;
+
+ let mut data = read_file()?;
+ let hashed_secret = proxmox_sys::crypt::encrypt_pw(secret)?;
+ data.insert(tokenid.clone(), hashed_secret);
+ write_file(data)?;
+
+ Ok(())
+}
+
+/// 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()?;
+
+ let mut data = read_file()?;
+ data.remove(tokenid);
+ write_file(data)?;
+
+ Ok(())
+}
--
2.39.2
_______________________________________________
pbs-devel mailing list
pbs-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pbs-devel
next prev parent reply other threads:[~2024-06-19 9:54 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-06-19 9:54 [pbs-devel] [PATCH proxmox v3 0/7] add proxmox-access-control crate Shannon Sterz
2024-06-19 9:54 ` [pbs-devel] [PATCH proxmox v3 1/7] access-control: add the proxmox-access crate to reuse acl trees Shannon Sterz
2024-06-19 9:54 ` [pbs-devel] [PATCH proxmox v3 2/7] access-control: define `User`, `UserWithTokens` and `ApiTokens` types Shannon Sterz
2024-06-19 9:54 ` Shannon Sterz [this message]
2024-06-19 9:54 ` [pbs-devel] [PATCH proxmox v3 4/7] access-control: factor out user config handling Shannon Sterz
2024-06-19 9:54 ` [pbs-devel] [PATCH proxmox v3 5/7] access: increment user cache generation when saving acl config Shannon Sterz
2024-06-19 9:54 ` [pbs-devel] [PATCH proxmox v3 6/7] access: move to flatten `User` into `UserWithToken` Shannon Sterz
2024-06-19 9:54 ` [pbs-devel] [PATCH proxmox v3 7/7] access-control: split crate in `default` and `impl` features Shannon Sterz
2024-06-19 12:48 ` [pbs-devel] applied-series: [PATCH proxmox v3 0/7] add proxmox-access-control crate Wolfgang Bumiller
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=20240619095418.126368-4-s.sterz@proxmox.com \
--to=s.sterz@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.