diff options
author | Quentin Dufour <quentin@deuxfleurs.fr> | 2022-06-15 18:40:39 +0200 |
---|---|---|
committer | Quentin Dufour <quentin@deuxfleurs.fr> | 2022-06-15 18:40:39 +0200 |
commit | 6b5b53916efb4897643172fdf461291b4effcf48 (patch) | |
tree | 9030270809e8b2fd56bc91b19d82915ea8c85641 /src/login/static_provider.rs | |
parent | 2bbcb119c437a3d8ba5d747f76898faa5ad32d93 (diff) | |
parent | 0700e27127e4644dbd323b9a22d994209143fa2a (diff) | |
download | aerogramme-6b5b53916efb4897643172fdf461291b4effcf48.tar.gz aerogramme-6b5b53916efb4897643172fdf461291b4effcf48.zip |
Add LMTP support
Diffstat (limited to 'src/login/static_provider.rs')
-rw-r--r-- | src/login/static_provider.rs | 144 |
1 files changed, 98 insertions, 46 deletions
diff --git a/src/login/static_provider.rs b/src/login/static_provider.rs index a95ab24..6bbc717 100644 --- a/src/login/static_provider.rs +++ b/src/login/static_provider.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::sync::Arc; use anyhow::{anyhow, bail, Result}; use async_trait::async_trait; @@ -10,16 +11,34 @@ use crate::login::*; pub struct StaticLoginProvider { default_bucket: Option<String>, - users: HashMap<String, LoginStaticUser>, + users: HashMap<String, Arc<LoginStaticUser>>, + users_by_email: HashMap<String, Arc<LoginStaticUser>>, + k2v_region: Region, s3_region: Region, } impl StaticLoginProvider { pub fn new(config: LoginStaticConfig, k2v_region: Region, s3_region: Region) -> Result<Self> { + let users = config + .users + .into_iter() + .map(|(k, v)| (k, Arc::new(v))) + .collect::<HashMap<_, _>>(); + let mut users_by_email = HashMap::new(); + for (_, u) in users.iter() { + for m in u.email_addresses.iter() { + if users_by_email.contains_key(m) { + bail!("Several users have same email address: {}", m); + } + users_by_email.insert(m.clone(), u.clone()); + } + } + Ok(Self { default_bucket: config.default_bucket, - users: config.users, + users, + users_by_email, k2v_region, s3_region, }) @@ -30,54 +49,87 @@ impl StaticLoginProvider { impl LoginProvider for StaticLoginProvider { async fn login(&self, username: &str, password: &str) -> Result<Credentials> { tracing::debug!(user=%username, "login"); - match self.users.get(username) { + let user = match self.users.get(username) { None => bail!("User {} does not exist", username), - Some(u) => { - tracing::debug!(user=%username, "verify password"); - if !verify_password(password, &u.password)? { - bail!("Wrong password"); - } - tracing::debug!(user=%username, "fetch bucket"); - let bucket = u - .bucket - .clone() - .or_else(|| self.default_bucket.clone()) - .ok_or(anyhow!( - "No bucket configured and no default bucket specieid" - ))?; - - tracing::debug!(user=%username, "fetch configuration"); - let storage = StorageCredentials { - k2v_region: self.k2v_region.clone(), - s3_region: self.s3_region.clone(), - aws_access_key_id: u.aws_access_key_id.clone(), - aws_secret_access_key: u.aws_secret_access_key.clone(), - bucket, - }; + Some(u) => u, + }; - tracing::debug!(user=%username, "fetch keys"); - let keys = match (&u.master_key, &u.secret_key) { - (Some(m), Some(s)) => { - let master_key = Key::from_slice(&base64::decode(m)?) - .ok_or(anyhow!("Invalid master key"))?; - let secret_key = SecretKey::from_slice(&base64::decode(s)?) - .ok_or(anyhow!("Invalid secret key"))?; - CryptoKeys::open_without_password(&storage, &master_key, &secret_key).await? - } - (None, None) => { - let user_secrets = UserSecrets { - user_secret: u.user_secret.clone(), - alternate_user_secrets: u.alternate_user_secrets.clone(), - }; - CryptoKeys::open(&storage, &user_secrets, password).await? - } - _ => bail!("Either both master and secret key or none of them must be specified for user"), - }; + tracing::debug!(user=%username, "verify password"); + if !verify_password(password, &user.password)? { + bail!("Wrong password"); + } + + tracing::debug!(user=%username, "fetch bucket"); + let bucket = user + .bucket + .clone() + .or_else(|| self.default_bucket.clone()) + .ok_or(anyhow!( + "No bucket configured and no default bucket specieid" + ))?; + + tracing::debug!(user=%username, "fetch keys"); + let storage = StorageCredentials { + k2v_region: self.k2v_region.clone(), + s3_region: self.s3_region.clone(), + aws_access_key_id: user.aws_access_key_id.clone(), + aws_secret_access_key: user.aws_secret_access_key.clone(), + bucket, + }; - tracing::debug!(user=%username, "logged"); - Ok(Credentials { storage, keys }) + let keys = match (&user.master_key, &user.secret_key) { + (Some(m), Some(s)) => { + let master_key = + Key::from_slice(&base64::decode(m)?).ok_or(anyhow!("Invalid master key"))?; + let secret_key = SecretKey::from_slice(&base64::decode(s)?) + .ok_or(anyhow!("Invalid secret key"))?; + CryptoKeys::open_without_password(&storage, &master_key, &secret_key).await? } - } + (None, None) => { + let user_secrets = UserSecrets { + user_secret: user.user_secret.clone(), + alternate_user_secrets: user.alternate_user_secrets.clone(), + }; + CryptoKeys::open(&storage, &user_secrets, password).await? + } + _ => bail!( + "Either both master and secret key or none of them must be specified for user" + ), + }; + + tracing::debug!(user=%username, "logged"); + Ok(Credentials { storage, keys }) + } + + async fn public_login(&self, email: &str) -> Result<PublicCredentials> { + let user = match self.users_by_email.get(email) { + None => bail!("No user for email address {}", email), + Some(u) => u, + }; + + let bucket = user + .bucket + .clone() + .or_else(|| self.default_bucket.clone()) + .ok_or(anyhow!( + "No bucket configured and no default bucket specieid" + ))?; + + let storage = StorageCredentials { + k2v_region: self.k2v_region.clone(), + s3_region: self.s3_region.clone(), + aws_access_key_id: user.aws_access_key_id.clone(), + aws_secret_access_key: user.aws_secret_access_key.clone(), + bucket, + }; + + let k2v_client = storage.k2v_client()?; + let (_, public_key) = CryptoKeys::load_salt_and_public(&k2v_client).await?; + + Ok(PublicCredentials { + storage, + public_key, + }) } } |