aboutsummaryrefslogtreecommitdiff
path: root/src/login/static_provider.rs
diff options
context:
space:
mode:
authorQuentin Dufour <quentin@deuxfleurs.fr>2022-06-15 18:40:39 +0200
committerQuentin Dufour <quentin@deuxfleurs.fr>2022-06-15 18:40:39 +0200
commit6b5b53916efb4897643172fdf461291b4effcf48 (patch)
tree9030270809e8b2fd56bc91b19d82915ea8c85641 /src/login/static_provider.rs
parent2bbcb119c437a3d8ba5d747f76898faa5ad32d93 (diff)
parent0700e27127e4644dbd323b9a22d994209143fa2a (diff)
downloadaerogramme-6b5b53916efb4897643172fdf461291b4effcf48.tar.gz
aerogramme-6b5b53916efb4897643172fdf461291b4effcf48.zip
Add LMTP support
Diffstat (limited to 'src/login/static_provider.rs')
-rw-r--r--src/login/static_provider.rs144
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,
+ })
}
}