auth: Remove unused UserStore trait and put app_tokens into User struct

This commit is contained in:
Lennart
2025-01-29 10:28:07 +01:00
parent 8fda600e7f
commit 21af6b0535
5 changed files with 23 additions and 40 deletions

View File

@@ -1,7 +1,6 @@
pub mod middleware;
pub mod static_user_store;
pub mod user;
pub mod user_store;
use crate::error::Error;
use async_trait::async_trait;

View File

@@ -7,31 +7,18 @@ use super::AuthenticationProvider;
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct StaticUserStoreConfig {
pub users: Vec<UserEntry>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct UserEntry {
#[serde(flatten)]
pub user: User,
#[serde(default)]
pub app_tokens: Vec<String>,
pub users: Vec<User>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct StaticUserStore {
pub users: HashMap<String, UserEntry>,
pub users: HashMap<String, User>,
}
impl StaticUserStore {
pub fn new(config: StaticUserStoreConfig) -> Self {
Self {
users: HashMap::from_iter(
config
.users
.into_iter()
.map(|user_entry| (user_entry.user.id.clone(), user_entry)),
),
users: HashMap::from_iter(config.users.into_iter().map(|user| (user.id.clone(), user))),
}
}
}
@@ -39,26 +26,26 @@ impl StaticUserStore {
#[async_trait]
impl AuthenticationProvider for StaticUserStore {
async fn validate_user_token(&self, user_id: &str, token: &str) -> Result<Option<User>, Error> {
let user_entry: UserEntry = match self.users.get(user_id) {
let user: User = match self.users.get(user_id) {
Some(user) => user.clone(),
None => return Ok(None),
};
// Try app tokens first since they are cheaper to calculate
// They can afford less iterations since they can be generated with high entropy
for app_token in &user_entry.app_tokens {
for app_token in &user.app_tokens {
if password_auth::verify_password(token, app_token).is_ok() {
return Ok(Some(user_entry.user));
return Ok(Some(user));
}
}
let password = match &user_entry.user.password {
let password = match &user.password {
Some(password) => password,
None => return Ok(None),
};
if password_auth::verify_password(token, password).is_ok() {
return Ok(Some(user_entry.user));
return Ok(Some(user));
}
Ok(None)

View File

@@ -12,6 +12,12 @@ pub struct User {
pub id: String,
pub displayname: Option<String>,
pub password: Option<String>,
#[serde(default)]
pub app_tokens: Vec<String>,
#[serde(default)]
pub groups: Vec<String>,
#[serde(skip)]
pub inherited_groups: Vec<String>,
}
#[derive(Clone, Debug, Display)]

View File

@@ -1,8 +0,0 @@
use crate::{auth::User, error::Error};
use async_trait::async_trait;
#[async_trait]
pub trait UserStore: Send + Sync + 'static {
async fn get_user(&self, id: &str) -> Result<Option<User>, Error>;
async fn put_user(&self, user: User) -> Result<(), Error>;
}

View File

@@ -4,7 +4,7 @@ use password_hash::PasswordHasher;
use pbkdf2::Params;
use rand::{rngs::OsRng, RngCore};
use rustical_frontend::FrontendConfig;
use rustical_store::auth::{static_user_store::UserEntry, StaticUserStoreConfig, User};
use rustical_store::auth::{StaticUserStoreConfig, User};
use crate::config::{
AuthConfig, Config, DataStoreConfig, DavPushConfig, HttpConfig, SqliteDataStoreConfig,
@@ -26,15 +26,14 @@ pub fn cmd_gen_config(_args: GenConfigArgs) -> anyhow::Result<()> {
let config = Config {
http: HttpConfig::default(),
auth: AuthConfig::Static(StaticUserStoreConfig {
users: vec![UserEntry {
user: User {
id: "default".to_owned(),
displayname: Some("Default user".to_owned()),
password: Some(
"generate a password hash with rustical pwhash --algorithm argon2"
.to_owned(),
),
},
users: vec![User {
id: "default".to_owned(),
displayname: Some("Default user".to_owned()),
password: Some(
"generate a password hash with rustical pwhash --algorithm argon2".to_owned(),
),
groups: vec![],
inherited_groups: vec![],
app_tokens: vec![
"generate an app token hash with rustical pwhash --algorithm pbkdf2".to_owned(),
],