Hook up auth

This commit is contained in:
Michael Zhang 2021-11-04 14:30:59 -05:00
parent 08d2e8c4b4
commit 6f504dc71c
Signed by: michael
GPG key ID: BDA47A31A3C8EE6B
9 changed files with 69 additions and 30 deletions

1
Cargo.lock generated
View file

@ -1130,6 +1130,7 @@ dependencies = [
"maplit", "maplit",
"nom", "nom",
"panorama-proto-common", "panorama-proto-common",
"serde",
"stderrlog", "stderrlog",
"tokio", "tokio",
"tokio-rustls 0.23.1", "tokio-rustls 0.23.1",

View file

@ -9,6 +9,7 @@ use std::io::Read;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use anyhow::Result; use anyhow::Result;
use panorama_imap::client::auth::ImapAuth;
#[cfg(feature = "config-watch")] #[cfg(feature = "config-watch")]
pub use self::watcher::{spawn_config_watcher_system, ConfigWatcher}; pub use self::watcher::{spawn_config_watcher_system, ConfigWatcher};
@ -62,21 +63,6 @@ pub struct ImapConfig {
pub auth: ImapAuth, pub auth: ImapAuth,
} }
/// Method of authentication for the IMAP server
#[derive(Serialize, Deserialize, Clone, Derivative)]
#[derivative(Debug)]
#[serde(tag = "auth")]
pub enum ImapAuth {
/// Use plain username/password authentication
#[serde(rename = "plain")]
Plain {
username: String,
#[derivative(Debug = "ignore")]
password: String,
},
}
/// Describes when to perform the TLS handshake /// Describes when to perform the TLS handshake
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub enum TlsMethod { pub enum TlsMethod {

View file

@ -49,9 +49,11 @@ pub async fn mail_main(
.tls(matches!(acct.imap.tls, TlsMethod::On)) .tls(matches!(acct.imap.tls, TlsMethod::On))
.build()?; .build()?;
let pool_config = PoolConfig { let pool_config = PoolConfig {
auth_config: acct.imap.auth,
client_config,
max_connections: 10, max_connections: 10,
}; };
let pool = ImapPool::new(client_config, pool_config); let pool = ImapPool::new(pool_config);
// grab one connection from that pool and start running a background // grab one connection from that pool and start running a background
// synchronization thread // synchronization thread

View file

@ -13,8 +13,9 @@ readme = "README.md"
workspace = ".." workspace = ".."
[features] [features]
default = ["pool", "rfc2177", "rfc6154"] default = ["serialize", "pool", "rfc2177", "rfc6154"]
low-level = [] low-level = []
serialize = ["serde/derive"]
pool = ["crossbeam"] pool = ["crossbeam"]
rfc2087 = [] # quota rfc2087 = [] # quota
rfc2177 = [] # idle rfc2177 = [] # idle
@ -41,10 +42,12 @@ tokio-util = { version = "0.6.9", features = ["codec"] }
webpki-roots = "0.22.1" webpki-roots = "0.22.1"
panorama-proto-common = { path = "../proto-common" } panorama-proto-common = { path = "../proto-common" }
crossbeam = { version = "0.8.1", optional = true }
# for fuzzing # for fuzzing
arbitrary = { version = "1.0.2", optional = true, features = ["derive"] } arbitrary = { version = "1.0.2", optional = true, features = ["derive"] }
crossbeam = { version = "0.8.1", optional = true }
serde = { version = "1.0.130", optional = true }
[dev-dependencies] [dev-dependencies]
maplit = "1.0.2" maplit = "1.0.2"

View file

@ -4,8 +4,46 @@ use anyhow::Result;
use panorama_proto_common::Bytes; use panorama_proto_common::Bytes;
use crate::client::inner::Inner; use crate::client::inner::Inner;
use crate::interface::ImapClient;
use crate::proto::command::{Command, CommandLogin}; use crate::proto::command::{Command, CommandLogin};
/// Method of authentication for the IMAP server
#[cfg_attr(
feature = "serialize",
derive(Serialize, Deserialize, Clone, Derivative)
)]
#[derivative(Debug)]
#[serde(tag = "auth")]
pub enum ImapAuth {
/// Use plain username/password authentication
#[serde(rename = "plain")]
Plain {
username: String,
#[derivative(Debug = "ignore")]
password: String,
},
}
impl ImapAuth {
pub async fn perform_auth<C>(&self, inner: &mut Inner<C>) -> Result<()>
where
C: Client,
{
match self {
ImapAuth::Plain { username, password } => {
let command = Command::Login(CommandLogin {
userid: Bytes::from(username.clone()),
password: Bytes::from(password.clone()),
});
let result = inner.execute(command).await?;
todo!()
}
}
}
}
pub trait Client: pub trait Client:
AsyncRead + AsyncWrite + Unpin + Sync + Send + 'static AsyncRead + AsyncWrite + Unpin + Sync + Send + 'static
{ {

View file

@ -22,7 +22,7 @@ use crate::proto::{
}, },
}; };
use super::auth::AuthMethod; use super::auth::{AuthMethod, ImapAuth};
use super::inner::Inner; use super::inner::Inner;
use super::response_stream::ResponseStream; use super::response_stream::ResponseStream;
use super::tls::wrap_tls; use super::tls::wrap_tls;
@ -102,10 +102,7 @@ impl ClientUnauthenticated {
} }
} }
pub async fn auth( pub async fn auth(self, auth: &ImapAuth) -> Result<ClientAuthenticated> {
self,
auth: impl AuthMethod,
) -> Result<ClientAuthenticated> {
match self { match self {
// this is a no-op, we don't need to upgrade // this is a no-op, we don't need to upgrade
ClientUnauthenticated::Encrypted(mut inner) => { ClientUnauthenticated::Encrypted(mut inner) => {

View file

@ -1,6 +1,9 @@
use anyhow::Result; use anyhow::Result;
use crate::proto::response::Envelope; use crate::proto::{
command::Command,
response::{Envelope, Response},
};
#[async_trait] #[async_trait]
pub trait ImapClient { pub trait ImapClient {

View file

@ -15,6 +15,10 @@ extern crate log;
#[macro_use] #[macro_use]
extern crate panorama_proto_common; extern crate panorama_proto_common;
#[cfg(feature = "serialize")]
#[macro_use]
extern crate serde;
#[cfg(test)] #[cfg(test)]
#[macro_use] #[macro_use]
extern crate maplit; extern crate maplit;

View file

@ -4,7 +4,11 @@ use anyhow::Result;
use crossbeam::queue::ArrayQueue; use crossbeam::queue::ArrayQueue;
use tokio::sync::Semaphore; use tokio::sync::Semaphore;
use crate::{client::auth::{AuthMethod, Login}, interface::ImapClient, proto::response::Envelope}; use crate::{
client::auth::{ImapAuth, Login},
interface::ImapClient,
proto::response::Envelope,
};
use super::client::{ClientAuthenticated, Config, ConfigBuilder}; use super::client::{ClientAuthenticated, Config, ConfigBuilder};
@ -12,6 +16,7 @@ use super::client::{ClientAuthenticated, Config, ConfigBuilder};
pub struct PoolConfig { pub struct PoolConfig {
pub max_connections: usize, pub max_connections: usize,
pub client_config: Config, pub client_config: Config,
pub auth_config: ImapAuth,
} }
/// A pool of IMAP connections. /// A pool of IMAP connections.
@ -49,10 +54,11 @@ pub struct InnerPool {
impl InnerPool { impl InnerPool {
pub fn init(config: PoolConfig) -> Self { pub fn init(config: PoolConfig) -> Self {
let max_connections = config.max_connections;
InnerPool { InnerPool {
config, config,
semaphore: Semaphore::new(config.max_connections), semaphore: Semaphore::new(max_connections),
connections: ArrayQueue::new(config.max_connections), connections: ArrayQueue::new(max_connections),
} }
} }
@ -75,8 +81,7 @@ impl InnerPool {
debug!("Client connected to {}", self.config.client_config.hostname); debug!("Client connected to {}", self.config.client_config.hostname);
// authenticate // authenticate
let client_auth = client.auth(Login { let client_auth = client.auth(&self.config.auth_config);
});
} }
}; };