aboutsummaryrefslogtreecommitdiff
path: root/src/login
diff options
context:
space:
mode:
Diffstat (limited to 'src/login')
-rw-r--r--src/login/ldap_provider.rs53
-rw-r--r--src/login/mod.rs70
-rw-r--r--src/login/static_provider.rs63
3 files changed, 113 insertions, 73 deletions
diff --git a/src/login/ldap_provider.rs b/src/login/ldap_provider.rs
index a7f56e4..81e5879 100644
--- a/src/login/ldap_provider.rs
+++ b/src/login/ldap_provider.rs
@@ -30,7 +30,10 @@ enum BucketSource {
enum StorageSpecific {
InMemory,
- Garage { from_config: LdapGarageConfig, bucket_source: BucketSource },
+ Garage {
+ from_config: LdapGarageConfig,
+ bucket_source: BucketSource,
+ },
}
impl LdapLoginProvider {
@@ -57,22 +60,24 @@ impl LdapLoginProvider {
let specific = match config.storage {
LdapStorage::InMemory => StorageSpecific::InMemory,
LdapStorage::Garage(grgconf) => {
- let bucket_source = match (grgconf.default_bucket.clone(), grgconf.bucket_attr.clone()) {
- (Some(b), None) => BucketSource::Constant(b),
- (None, Some(a)) => BucketSource::Attr(a),
- _ => bail!("Must set `bucket` or `bucket_attr`, but not both"),
- };
+ let bucket_source =
+ match (grgconf.default_bucket.clone(), grgconf.bucket_attr.clone()) {
+ (Some(b), None) => BucketSource::Constant(b),
+ (None, Some(a)) => BucketSource::Attr(a),
+ _ => bail!("Must set `bucket` or `bucket_attr`, but not both"),
+ };
if let BucketSource::Attr(a) = &bucket_source {
attrs_to_retrieve.push(a.clone());
}
- StorageSpecific::Garage { from_config: grgconf, bucket_source }
- },
+ StorageSpecific::Garage {
+ from_config: grgconf,
+ bucket_source,
+ }
+ }
};
-
-
Ok(Self {
ldap_server: config.ldap_server,
pre_bind_on_login: config.pre_bind_on_login,
@@ -89,27 +94,32 @@ impl LdapLoginProvider {
async fn storage_creds_from_ldap_user(&self, user: &SearchEntry) -> Result<Builder> {
let storage: Builder = match &self.storage_specific {
- StorageSpecific::InMemory => self.in_memory_store.builder(
- &get_attr(user, &self.username_attr)?
- ).await,
- StorageSpecific::Garage { from_config, bucket_source } => {
+ StorageSpecific::InMemory => {
+ self.in_memory_store
+ .builder(&get_attr(user, &self.username_attr)?)
+ .await
+ }
+ StorageSpecific::Garage {
+ from_config,
+ bucket_source,
+ } => {
let aws_access_key_id = get_attr(user, &from_config.aws_access_key_id_attr)?;
- let aws_secret_access_key = get_attr(user, &from_config.aws_secret_access_key_attr)?;
+ let aws_secret_access_key =
+ get_attr(user, &from_config.aws_secret_access_key_attr)?;
let bucket = match bucket_source {
BucketSource::Constant(b) => b.clone(),
BucketSource::Attr(a) => get_attr(user, &a)?,
};
-
storage::garage::GarageBuilder::new(storage::garage::GarageConf {
- region: from_config.aws_region.clone(),
+ region: from_config.aws_region.clone(),
s3_endpoint: from_config.s3_endpoint.clone(),
k2v_endpoint: from_config.k2v_endpoint.clone(),
- aws_access_key_id,
- aws_secret_access_key,
+ aws_access_key_id,
+ aws_secret_access_key,
bucket,
})?
- },
+ }
};
Ok(storage)
@@ -172,7 +182,6 @@ impl LoginProvider for LdapLoginProvider {
drop(ldap);
-
Ok(Credentials { storage, keys })
}
@@ -215,7 +224,7 @@ impl LoginProvider for LdapLoginProvider {
let cr = CryptoRoot(crstr);
let public_key = cr.public_key()?;
- // storage
+ // storage
let storage = self.storage_creds_from_ldap_user(&user).await?;
drop(ldap);
diff --git a/src/login/mod.rs b/src/login/mod.rs
index 3369ac2..2926738 100644
--- a/src/login/mod.rs
+++ b/src/login/mod.rs
@@ -1,8 +1,8 @@
pub mod ldap_provider;
pub mod static_provider;
-use std::sync::Arc;
use base64::Engine;
+use std::sync::Arc;
use anyhow::{anyhow, bail, Context, Result};
use async_trait::async_trait;
@@ -45,7 +45,7 @@ pub struct PublicCredentials {
pub public_key: PublicKey,
}
-use serde::{Serialize, Deserialize};
+use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct CryptoRoot(pub String);
@@ -73,47 +73,59 @@ impl CryptoRoot {
pub fn public_key(&self) -> Result<PublicKey> {
match self.0.splitn(4, ':').collect::<Vec<&str>>()[..] {
- [ "aero", "cryptoroot", "pass", b64blob ] => {
+ ["aero", "cryptoroot", "pass", b64blob] => {
let blob = base64::engine::general_purpose::STANDARD_NO_PAD.decode(b64blob)?;
if blob.len() < 32 {
- bail!("Decoded data is {} bytes long, expect at least 32 bytes", blob.len());
+ bail!(
+ "Decoded data is {} bytes long, expect at least 32 bytes",
+ blob.len()
+ );
}
PublicKey::from_slice(&blob[..32]).context("must be a valid public key")
- },
- [ "aero", "cryptoroot", "cleartext", b64blob ] => {
+ }
+ ["aero", "cryptoroot", "cleartext", b64blob] => {
let blob = base64::engine::general_purpose::STANDARD_NO_PAD.decode(b64blob)?;
Ok(CryptoKeys::deserialize(&blob)?.public)
- },
- [ "aero", "cryptoroot", "incoming", b64blob ] => {
+ }
+ ["aero", "cryptoroot", "incoming", b64blob] => {
let blob = base64::engine::general_purpose::STANDARD_NO_PAD.decode(b64blob)?;
if blob.len() < 32 {
- bail!("Decoded data is {} bytes long, expect at least 32 bytes", blob.len());
+ bail!(
+ "Decoded data is {} bytes long, expect at least 32 bytes",
+ blob.len()
+ );
}
PublicKey::from_slice(&blob[..32]).context("must be a valid public key")
- },
- [ "aero", "cryptoroot", "keyring", _ ] => {
+ }
+ ["aero", "cryptoroot", "keyring", _] => {
bail!("keyring is not yet implemented!")
- },
- _ => bail!(format!("passed string '{}' is not a valid cryptoroot", self.0)),
+ }
+ _ => bail!(format!(
+ "passed string '{}' is not a valid cryptoroot",
+ self.0
+ )),
}
}
pub fn crypto_keys(&self, password: &str) -> Result<CryptoKeys> {
match self.0.splitn(4, ':').collect::<Vec<&str>>()[..] {
- [ "aero", "cryptoroot", "pass", b64blob ] => {
+ ["aero", "cryptoroot", "pass", b64blob] => {
let blob = base64::engine::general_purpose::STANDARD_NO_PAD.decode(b64blob)?;
CryptoKeys::password_open(password, &blob)
- },
- [ "aero", "cryptoroot", "cleartext", b64blob ] => {
+ }
+ ["aero", "cryptoroot", "cleartext", b64blob] => {
let blob = base64::engine::general_purpose::STANDARD_NO_PAD.decode(b64blob)?;
CryptoKeys::deserialize(&blob)
- },
- [ "aero", "cryptoroot", "incoming", _ ] => {
+ }
+ ["aero", "cryptoroot", "incoming", _] => {
bail!("incoming cryptoroot does not contain a crypto key!")
- },
- [ "aero", "cryptoroot", "keyring", _ ] =>{
+ }
+ ["aero", "cryptoroot", "keyring", _] => {
bail!("keyring is not yet implemented!")
- },
- _ => bail!(format!("passed string '{}' is not a valid cryptoroot", self.0)),
+ }
+ _ => bail!(format!(
+ "passed string '{}' is not a valid cryptoroot",
+ self.0
+ )),
}
}
}
@@ -132,9 +144,6 @@ pub struct CryptoKeys {
// ----
-
-
-
impl CryptoKeys {
/// Initialize a new cryptography root
pub fn init() -> Self {
@@ -202,7 +211,11 @@ fn derive_password_key(kdf_salt: &[u8], password: &str) -> Result<Key> {
Ok(Key::from_slice(&argon2_kdf(kdf_salt, password.as_bytes(), 32)?).unwrap())
}
-fn try_open_encrypted_keys(kdf_salt: &[u8], password: &str, encrypted_keys: &[u8]) -> Result<Vec<u8>> {
+fn try_open_encrypted_keys(
+ kdf_salt: &[u8],
+ password: &str,
+ encrypted_keys: &[u8],
+) -> Result<Vec<u8>> {
let password_key = derive_password_key(kdf_salt, password)?;
open(encrypted_keys, &password_key)
}
@@ -210,7 +223,7 @@ fn try_open_encrypted_keys(kdf_salt: &[u8], password: &str, encrypted_keys: &[u8
// ---- UTIL ----
pub fn argon2_kdf(salt: &[u8], password: &[u8], output_len: usize) -> Result<Vec<u8>> {
- use argon2::{Algorithm, Argon2, ParamsBuilder, PasswordHasher, Version, password_hash};
+ use argon2::{password_hash, Algorithm, Argon2, ParamsBuilder, PasswordHasher, Version};
let params = ParamsBuilder::new()
.output_len(output_len)
@@ -219,7 +232,8 @@ pub fn argon2_kdf(salt: &[u8], password: &[u8], output_len: usize) -> Result<Vec
let argon2 = Argon2::new(Algorithm::default(), Version::default(), params);
let b64_salt = base64::engine::general_purpose::STANDARD_NO_PAD.encode(salt);
- let valid_salt = password_hash::Salt::from_b64(&b64_salt).map_err(|e| anyhow!("Invalid salt, error {}", e))?;
+ let valid_salt = password_hash::Salt::from_b64(&b64_salt)
+ .map_err(|e| anyhow!("Invalid salt, error {}", e))?;
let hash = argon2
.hash_password(password, valid_salt)
.map_err(|e| anyhow!("Unable to hash: {}", e))?;
diff --git a/src/login/static_provider.rs b/src/login/static_provider.rs
index b11123c..1e1ecbf 100644
--- a/src/login/static_provider.rs
+++ b/src/login/static_provider.rs
@@ -1,8 +1,8 @@
use std::collections::HashMap;
-use std::sync::Arc;
use std::path::PathBuf;
-use tokio::sync::watch;
+use std::sync::Arc;
use tokio::signal::unix::{signal, SignalKind};
+use tokio::sync::watch;
use anyhow::{anyhow, bail, Result};
use async_trait::async_trait;
@@ -28,7 +28,8 @@ pub struct StaticLoginProvider {
}
pub async fn update_user_list(config: PathBuf, up: watch::Sender<UserDatabase>) -> Result<()> {
- let mut stream = signal(SignalKind::user_defined1()).expect("failed to install SIGUSR1 signal hander for reload");
+ let mut stream = signal(SignalKind::user_defined1())
+ .expect("failed to install SIGUSR1 signal hander for reload");
loop {
let ulist: UserList = match read_config(config.clone()) {
@@ -42,7 +43,12 @@ pub async fn update_user_list(config: PathBuf, up: watch::Sender<UserDatabase>)
let users = ulist
.into_iter()
- .map(|(username, config)| (username.clone() , Arc::new(ContextualUserEntry { username, config })))
+ .map(|(username, config)| {
+ (
+ username.clone(),
+ Arc::new(ContextualUserEntry { username, config }),
+ )
+ })
.collect::<HashMap<_, _>>();
let mut users_by_email = HashMap::new();
@@ -51,14 +57,18 @@ pub async fn update_user_list(config: PathBuf, up: watch::Sender<UserDatabase>)
if users_by_email.contains_key(m) {
tracing::warn!("Several users have the same email address: {}", m);
stream.recv().await;
- continue
+ continue;
}
users_by_email.insert(m.clone(), u.clone());
}
}
tracing::info!("{} users loaded", users.len());
- up.send(UserDatabase { users, users_by_email }).context("update user db config")?;
+ up.send(UserDatabase {
+ users,
+ users_by_email,
+ })
+ .context("update user db config")?;
stream.recv().await;
tracing::info!("Received SIGUSR1, reloading");
}
@@ -71,7 +81,10 @@ impl StaticLoginProvider {
tokio::spawn(update_user_list(config.user_list, tx));
rx.changed().await?;
- Ok(Self { user_db: rx, in_memory_store: storage::in_memory::MemDb::new() })
+ Ok(Self {
+ user_db: rx,
+ in_memory_store: storage::in_memory::MemDb::new(),
+ })
}
}
@@ -95,14 +108,16 @@ impl LoginProvider for StaticLoginProvider {
tracing::debug!(user=%username, "fetch keys");
let storage: storage::Builder = match &user.config.storage {
StaticStorage::InMemory => self.in_memory_store.builder(username).await,
- StaticStorage::Garage(grgconf) => storage::garage::GarageBuilder::new(storage::garage::GarageConf {
- region: grgconf.aws_region.clone(),
- k2v_endpoint: grgconf.k2v_endpoint.clone(),
- s3_endpoint: grgconf.s3_endpoint.clone(),
- aws_access_key_id: grgconf.aws_access_key_id.clone(),
- aws_secret_access_key: grgconf.aws_secret_access_key.clone(),
- bucket: grgconf.bucket.clone(),
- })?,
+ StaticStorage::Garage(grgconf) => {
+ storage::garage::GarageBuilder::new(storage::garage::GarageConf {
+ region: grgconf.aws_region.clone(),
+ k2v_endpoint: grgconf.k2v_endpoint.clone(),
+ s3_endpoint: grgconf.s3_endpoint.clone(),
+ aws_access_key_id: grgconf.aws_access_key_id.clone(),
+ aws_secret_access_key: grgconf.aws_secret_access_key.clone(),
+ bucket: grgconf.bucket.clone(),
+ })?
+ }
};
let cr = CryptoRoot(user.config.crypto_root.clone());
@@ -124,14 +139,16 @@ impl LoginProvider for StaticLoginProvider {
let storage: storage::Builder = match &user.config.storage {
StaticStorage::InMemory => self.in_memory_store.builder(&user.username).await,
- StaticStorage::Garage(grgconf) => storage::garage::GarageBuilder::new(storage::garage::GarageConf {
- region: grgconf.aws_region.clone(),
- k2v_endpoint: grgconf.k2v_endpoint.clone(),
- s3_endpoint: grgconf.s3_endpoint.clone(),
- aws_access_key_id: grgconf.aws_access_key_id.clone(),
- aws_secret_access_key: grgconf.aws_secret_access_key.clone(),
- bucket: grgconf.bucket.clone(),
- })?,
+ StaticStorage::Garage(grgconf) => {
+ storage::garage::GarageBuilder::new(storage::garage::GarageConf {
+ region: grgconf.aws_region.clone(),
+ k2v_endpoint: grgconf.k2v_endpoint.clone(),
+ s3_endpoint: grgconf.s3_endpoint.clone(),
+ aws_access_key_id: grgconf.aws_access_key_id.clone(),
+ aws_secret_access_key: grgconf.aws_secret_access_key.clone(),
+ bucket: grgconf.bucket.clone(),
+ })?
+ }
};
let cr = CryptoRoot(user.config.crypto_root.clone());