mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
Introduce BackendHandler trait and impl
This commit is contained in:
parent
1a947358fa
commit
ff4e986a0d
@ -3,6 +3,7 @@ authors = ["Valentin Tolmer <valentin@tolmer.fr>", "Steve Barrau <steve.barrau@g
|
||||
edition = "2018"
|
||||
name = "lldap"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
actix = "0.11.0-beta.3"
|
||||
actix-rt = "2.1.0"
|
||||
@ -29,3 +30,6 @@ tracing-subscriber = "*"
|
||||
[dependencies.figment]
|
||||
features = ["toml", "env"]
|
||||
version = "*"
|
||||
|
||||
[dev-dependencies]
|
||||
mockall = "0.9.1"
|
||||
|
49
src/domain/handler.rs
Normal file
49
src/domain/handler.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use crate::infra::configuration::Configuration;
|
||||
use anyhow::{bail, Result};
|
||||
use sqlx::any::AnyPool;
|
||||
|
||||
pub struct BindRequest {
|
||||
pub name: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
pub struct SearchRequest {}
|
||||
|
||||
pub struct SearchResponse {}
|
||||
|
||||
pub trait BackendHandler: Clone + Send {
|
||||
fn bind(&mut self, request: BindRequest) -> Result<()>;
|
||||
fn search(&mut self, request: SearchRequest) -> Result<SearchResponse>;
|
||||
}
|
||||
|
||||
#[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<SearchResponse> {
|
||||
Ok(SearchResponse {})
|
||||
}
|
||||
}
|
1
src/domain/mod.rs
Normal file
1
src/domain/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub mod handler;
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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<Backend: BackendHandler> {
|
||||
dn: String,
|
||||
sql_pool: AnyPool,
|
||||
backend_handler: Backend,
|
||||
}
|
||||
|
||||
impl LdapSession {
|
||||
impl<Backend: BackendHandler> LdapHandler<Backend> {
|
||||
pub fn do_bind(&mut self, sbr: &SimpleBindRequest) -> LdapMsg {
|
||||
if sbr.dn == "cn=Directory Manager" && sbr.pw == "password" {
|
||||
self.dn = sbr.dn.to_string();
|
||||
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()
|
||||
} else if sbr.dn == "" && sbr.pw == "" {
|
||||
self.dn = "Anonymous".to_string();
|
||||
sbr.gen_success()
|
||||
} else {
|
||||
sbr.gen_invalid_cred()
|
||||
}
|
||||
Err(_) => sbr.gen_invalid_cred(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,10 +84,10 @@ impl LdapSession {
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_incoming_message(
|
||||
async fn handle_incoming_message<Backend: BackendHandler>(
|
||||
msg: Result<LdapMsg, std::io::Error>,
|
||||
resp: &mut FramedWrite<WriteHalf<'_>, LdapCodec>,
|
||||
session: &mut LdapSession,
|
||||
session: &mut LdapHandler<Backend>,
|
||||
) -> Result<bool> {
|
||||
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<Backend>(
|
||||
config: &Configuration,
|
||||
sql_pool: AnyPool,
|
||||
backend_handler: Backend,
|
||||
server_builder: ServerBuilder,
|
||||
) -> Result<ServerBuilder> {
|
||||
) -> Result<ServerBuilder>
|
||||
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 {
|
||||
|
@ -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<Backend>(
|
||||
config: &Configuration,
|
||||
sql_pool: AnyPool,
|
||||
backend_handler: Backend,
|
||||
server_builder: ServerBuilder,
|
||||
) -> Result<ServerBuilder> {
|
||||
) -> Result<ServerBuilder>
|
||||
where
|
||||
Backend: BackendHandler + 'static,
|
||||
{
|
||||
use std::sync::atomic::AtomicUsize;
|
||||
use std::sync::atomic::Ordering;
|
||||
use tokio::io::AsyncReadExt;
|
||||
|
@ -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(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user