From ff4e986a0d2093666c5906d710e346daee0d001e Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Thu, 11 Mar 2021 10:14:15 +0100 Subject: [PATCH] Introduce BackendHandler trait and impl --- Cargo.toml | 4 +++ src/domain/handler.rs | 49 +++++++++++++++++++++++++++++++++++++ src/domain/mod.rs | 1 + src/infra/configuration.rs | 6 +++-- src/infra/ldap_server.rs | 50 +++++++++++++++++++++----------------- src/infra/tcp_server.rs | 11 ++++++--- src/main.rs | 7 ++++-- 7 files changed, 98 insertions(+), 30 deletions(-) create mode 100644 src/domain/handler.rs create mode 100644 src/domain/mod.rs diff --git a/Cargo.toml b/Cargo.toml index fd8668f..3014aca 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ authors = ["Valentin Tolmer ", "Steve Barrau Result<()>; + fn search(&mut self, request: SearchRequest) -> Result; +} + +#[derive(Debug, Clone)] +pub struct SqlBackendHandler { + config: Configuration, + sql_pool: AnyPool, + authenticated: bool, +} + +impl SqlBackendHandler { + pub fn new(config: Configuration, sql_pool: AnyPool) -> Self { + SqlBackendHandler { + config, + sql_pool, + authenticated: false, + } + } +} + +impl BackendHandler for SqlBackendHandler { + fn bind(&mut self, request: BindRequest) -> Result<()> { + if request.name == self.config.admin_dn && request.password == self.config.admin_password { + self.authenticated = true; + Ok(()) + } else { + bail!(r#"Authentication error for "{}""#, request.name) + } + } + + fn search(&mut self, request: SearchRequest) -> Result { + Ok(SearchResponse {}) + } +} diff --git a/src/domain/mod.rs b/src/domain/mod.rs new file mode 100644 index 0000000..062ae9d --- /dev/null +++ b/src/domain/mod.rs @@ -0,0 +1 @@ +pub mod handler; diff --git a/src/infra/configuration.rs b/src/infra/configuration.rs index f88ade3..b18eb12 100644 --- a/src/infra/configuration.rs +++ b/src/infra/configuration.rs @@ -13,7 +13,8 @@ pub struct Configuration { pub ldaps_port: u16, pub http_port: u16, pub secret_pepper: String, - pub some_text: String, + pub admin_dn: String, + pub admin_password: String, pub verbose: bool, } @@ -24,7 +25,8 @@ impl Default for Configuration { ldaps_port: 6360, http_port: 17170, secret_pepper: String::from("secretsecretpepper"), - some_text: String::new(), + admin_dn: String::new(), + admin_password: String::new(), verbose: false, } } diff --git a/src/infra/ldap_server.rs b/src/infra/ldap_server.rs index 6160174..eae7770 100644 --- a/src/infra/ldap_server.rs +++ b/src/infra/ldap_server.rs @@ -1,3 +1,4 @@ +use crate::domain::handler::BackendHandler; use crate::infra::configuration::Configuration; use actix_rt::net::TcpStream; use actix_server::ServerBuilder; @@ -6,28 +7,30 @@ use anyhow::bail; use anyhow::Result; use futures_util::future::ok; use log::*; -use sqlx::any::AnyPool; use tokio::net::tcp::WriteHalf; use tokio_util::codec::{FramedRead, FramedWrite}; use ldap3_server::simple::*; use ldap3_server::LdapCodec; -pub struct LdapSession { +pub struct LdapHandler { dn: String, - sql_pool: AnyPool, + backend_handler: Backend, } -impl LdapSession { +impl LdapHandler { pub fn do_bind(&mut self, sbr: &SimpleBindRequest) -> LdapMsg { - if sbr.dn == "cn=Directory Manager" && sbr.pw == "password" { - self.dn = sbr.dn.to_string(); - sbr.gen_success() - } else if sbr.dn == "" && sbr.pw == "" { - self.dn = "Anonymous".to_string(); - sbr.gen_success() - } else { - sbr.gen_invalid_cred() + match self + .backend_handler + .bind(crate::domain::handler::BindRequest { + name: sbr.dn.clone(), + password: sbr.pw.clone(), + }) { + Ok(()) => { + self.dn = sbr.dn.clone(); + sbr.gen_success() + } + Err(_) => sbr.gen_invalid_cred(), } } @@ -81,10 +84,10 @@ impl LdapSession { } } -async fn handle_incoming_message( +async fn handle_incoming_message( msg: Result, resp: &mut FramedWrite, LdapCodec>, - session: &mut LdapSession, + session: &mut LdapHandler, ) -> Result { use futures_util::SinkExt; use std::convert::TryFrom; @@ -122,27 +125,30 @@ async fn handle_incoming_message( Ok(true) } -pub fn build_ldap_server( +pub fn build_ldap_server( config: &Configuration, - sql_pool: AnyPool, + backend_handler: Backend, server_builder: ServerBuilder, -) -> Result { +) -> Result +where + Backend: BackendHandler + 'static, +{ use futures_util::StreamExt; Ok( server_builder.bind("ldap", ("0.0.0.0", config.ldap_port), move || { - let sql_pool = sql_pool.clone(); + let backend_handler = backend_handler.clone(); pipeline_factory(fn_service(move |mut stream: TcpStream| { - let sql_pool = sql_pool.clone(); + let backend_handler = backend_handler.clone(); async move { // Configure the codec etc. let (r, w) = stream.split(); let mut requests = FramedRead::new(r, LdapCodec); let mut resp = FramedWrite::new(w, LdapCodec); - let mut session = LdapSession { - dn: "Anonymous".to_string(), - sql_pool, + let mut session = LdapHandler { + dn: "Unauthenticated".to_string(), + backend_handler, }; while let Some(msg) = requests.next().await { diff --git a/src/infra/tcp_server.rs b/src/infra/tcp_server.rs index de8efd6..4fabfdd 100644 --- a/src/infra/tcp_server.rs +++ b/src/infra/tcp_server.rs @@ -1,3 +1,4 @@ +use crate::domain::handler::*; use crate::infra::configuration::Configuration; use actix_rt::net::TcpStream; use actix_server::ServerBuilder; @@ -5,14 +6,16 @@ use actix_service::pipeline_factory; use anyhow::{Context, Result}; use futures_util::future::ok; use log::*; -use sqlx::any::AnyPool; use std::sync::Arc; -pub fn build_tcp_server( +pub fn build_tcp_server( config: &Configuration, - sql_pool: AnyPool, + backend_handler: Backend, server_builder: ServerBuilder, -) -> Result { +) -> Result +where + Backend: BackendHandler + 'static, +{ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; use tokio::io::AsyncReadExt; diff --git a/src/main.rs b/src/main.rs index 3eacb6c..26db4bb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use futures_util::TryFutureExt; use log::*; use sqlx::any::AnyPoolOptions; +mod domain; mod infra; async fn run_server(config: Configuration) -> Result<()> { @@ -11,12 +12,14 @@ async fn run_server(config: Configuration) -> Result<()> { .max_connections(5) .connect("sqlite://users.db?mode=rwc") .await?; + let backend_handler = domain::handler::SqlBackendHandler::new(config.clone(), sql_pool.clone()); let server_builder = infra::ldap_server::build_ldap_server( &config, - sql_pool.clone(), + backend_handler.clone(), actix_server::Server::build(), )?; - let server_builder = infra::tcp_server::build_tcp_server(&config, sql_pool, server_builder)?; + let server_builder = + infra::tcp_server::build_tcp_server(&config, backend_handler, server_builder)?; server_builder.workers(1).run().await?; Ok(()) }