mirror of
https://git.proxmox.com/git/proxmox
synced 2025-11-07 05:33:05 +00:00
This is the PbsAuthenticator with the hardcoded shadow.json/lock configurable. Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
91 lines
3.3 KiB
Rust
91 lines
3.3 KiB
Rust
use std::future::Future;
|
|
use std::net::IpAddr;
|
|
use std::pin::Pin;
|
|
|
|
use anyhow::{bail, Error};
|
|
use serde_json::json;
|
|
|
|
use proxmox_product_config::open_secret_lockfile;
|
|
|
|
use crate::types::UsernameRef;
|
|
|
|
/// A simple password authenticator with a configurable path for a shadow json and lock file.
|
|
pub struct PasswordAuthenticator {
|
|
pub config_filename: &'static str,
|
|
pub lock_filename: &'static str,
|
|
}
|
|
|
|
impl crate::api::Authenticator for PasswordAuthenticator {
|
|
fn authenticate_user<'a>(
|
|
&'a self,
|
|
username: &'a UsernameRef,
|
|
password: &'a str,
|
|
client_ip: Option<&'a IpAddr>,
|
|
) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'a>> {
|
|
Box::pin(async move {
|
|
let data = proxmox_sys::fs::file_get_json(self.config_filename, Some(json!({})))?;
|
|
match data[username.as_str()].as_str() {
|
|
None => bail!("no password set"),
|
|
Some(enc_password) => {
|
|
proxmox_sys::crypt::verify_crypt_pw(password, enc_password)?;
|
|
|
|
// if the password hash is not based on the current hashing function (as
|
|
// identified by its prefix), rehash the password.
|
|
if !enc_password.starts_with(proxmox_sys::crypt::HASH_PREFIX) {
|
|
// only log that we could not upgrade a password, we already know that the
|
|
// user has a valid password, no reason the deny to log in attempt.
|
|
if let Err(e) = self.store_password(username, password, client_ip) {
|
|
log::warn!("could not upgrade a users password! - {e}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Ok(())
|
|
})
|
|
}
|
|
|
|
fn store_password(
|
|
&self,
|
|
username: &UsernameRef,
|
|
password: &str,
|
|
_client_ip: Option<&IpAddr>,
|
|
) -> Result<(), Error> {
|
|
let enc_password = proxmox_sys::crypt::encrypt_pw(password)?;
|
|
|
|
let _guard = open_secret_lockfile(self.lock_filename, None, true);
|
|
let mut data = proxmox_sys::fs::file_get_json(self.config_filename, Some(json!({})))?;
|
|
data[username.as_str()] = enc_password.into();
|
|
|
|
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
|
|
let options = proxmox_sys::fs::CreateOptions::new()
|
|
.perm(mode)
|
|
.owner(nix::unistd::ROOT)
|
|
.group(nix::unistd::Gid::from_raw(0));
|
|
|
|
let data = serde_json::to_vec_pretty(&data)?;
|
|
proxmox_sys::fs::replace_file(self.config_filename, &data, options, true)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn remove_password(&self, username: &UsernameRef) -> Result<(), Error> {
|
|
let _guard = open_secret_lockfile(self.lock_filename, None, true);
|
|
|
|
let mut data = proxmox_sys::fs::file_get_json(self.config_filename, Some(json!({})))?;
|
|
if let Some(map) = data.as_object_mut() {
|
|
map.remove(username.as_str());
|
|
}
|
|
|
|
let mode = nix::sys::stat::Mode::from_bits_truncate(0o0600);
|
|
let options = proxmox_sys::fs::CreateOptions::new()
|
|
.perm(mode)
|
|
.owner(nix::unistd::ROOT)
|
|
.group(nix::unistd::Gid::from_raw(0));
|
|
|
|
let data = serde_json::to_vec_pretty(&data)?;
|
|
proxmox_sys::fs::replace_file(self.config_filename, &data, options, true)?;
|
|
|
|
Ok(())
|
|
}
|
|
}
|