WIP: sorry this does not compiles

This commit is contained in:
Thomas Wickham 2021-03-06 23:39:34 +01:00
parent ad445ac7b7
commit 6eaf859ba9
5 changed files with 287 additions and 8 deletions

View File

@ -4,21 +4,24 @@ edition = "2018"
name = "lldap" name = "lldap"
version = "0.1.0" version = "0.1.0"
[dependencies] [dependencies]
actix = "*" actix = "0.11.0-beta.3"
actix-rt = "1.1.1" actix-rt = "*"
actix-server = "*" actix-server = "2.0.0-beta.3"
actix-service = "*" actix-service = "2.0.0-beta.4"
actix-web = "*" actix-web = "4.0.0-beta.3"
anyhow = "*" anyhow = "*"
clap = "3.0.0-beta.2" clap = "3.0.0-beta.2"
futures = "*"
futures-util = "*" futures-util = "*"
http = "*" http = "*"
ldap3_server = "*"
log = "*" log = "*"
serde = "*" serde = "*"
thiserror = "*" thiserror = "*"
tokio = "0.2.25" tokio = { version = "*", features = ["full"] }
tokio-util = "*"
tracing = "*" tracing = "*"
tracing-actix-web = "*" tracing-actix-web = "0.3.0-beta.2"
tracing-log = "*" tracing-log = "*"
tracing-subscriber = "*" tracing-subscriber = "*"

150
examples/ldap_server.rs Normal file
View File

@ -0,0 +1,150 @@
use tokio::net::{TcpListener, TcpStream};
// use tokio::stream::StreamExt;
use futures::SinkExt;
use futures::StreamExt;
use std::convert::TryFrom;
use std::net;
use std::str::FromStr;
use tokio_util::codec::{FramedRead, FramedWrite};
use ldap3_server::simple::*;
use ldap3_server::LdapCodec;
pub struct LdapSession {
dn: String,
}
impl LdapSession {
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()
}
}
pub fn do_search(&mut self, lsr: &SearchRequest) -> Vec<LdapMsg> {
vec![
lsr.gen_result_entry(LdapSearchResultEntry {
dn: "cn=hello,dc=example,dc=com".to_string(),
attributes: vec![
LdapPartialAttribute {
atype: "objectClass".to_string(),
vals: vec!["cursed".to_string()],
},
LdapPartialAttribute {
atype: "cn".to_string(),
vals: vec!["hello".to_string()],
},
],
}),
lsr.gen_result_entry(LdapSearchResultEntry {
dn: "cn=world,dc=example,dc=com".to_string(),
attributes: vec![
LdapPartialAttribute {
atype: "objectClass".to_string(),
vals: vec!["cursed".to_string()],
},
LdapPartialAttribute {
atype: "cn".to_string(),
vals: vec!["world".to_string()],
},
],
}),
lsr.gen_success(),
]
}
pub fn do_whoami(&mut self, wr: &WhoamiRequest) -> LdapMsg {
wr.gen_success(format!("dn: {}", self.dn).as_str())
}
}
async fn handle_client(socket: TcpStream, _paddr: net::SocketAddr) {
// Configure the codec etc.
let (r, w) = tokio::io::split(socket);
let mut reqs = FramedRead::new(r, LdapCodec);
let mut resp = FramedWrite::new(w, LdapCodec);
let mut session = LdapSession {
dn: "Anonymous".to_string(),
};
while let Some(msg) = reqs.next().await {
let server_op = match msg
.map_err(|_e| ())
.and_then(|msg| ServerOps::try_from(msg))
{
Ok(v) => v,
Err(_) => {
let _err = resp
.send(DisconnectionNotice::gen(
LdapResultCode::Other,
"Internal Server Error",
))
.await;
let _err = resp.flush().await;
return;
}
};
let result = match server_op {
ServerOps::SimpleBind(sbr) => vec![session.do_bind(&sbr)],
ServerOps::Search(sr) => session.do_search(&sr),
ServerOps::Unbind(_) => {
// No need to notify on unbind (per rfc4511)
return;
}
ServerOps::Whoami(wr) => vec![session.do_whoami(&wr)],
};
for rmsg in result.into_iter() {
if let Err(_) = resp.send(rmsg).await {
return;
}
}
if let Err(_) = resp.flush().await {
return;
}
}
// Client disconnected
}
async fn acceptor(listener: Box<TcpListener>) {
println!("start function");
loop {
println!("loop");
match listener.accept().await {
Ok((socket, paddr)) => {
println!("OK listener");
tokio::spawn(handle_client(socket, paddr));
}
Err(_e) => {
println!("Err listener");
//pass
}
}
}
}
#[tokio::main]
async fn main() -> () {
let addr = net::SocketAddr::from_str("0.0.0.0:12345").unwrap();
let listener = Box::new(TcpListener::bind(&addr).await.unwrap());
// Initiate the acceptor task.
let _handle = tokio::spawn(async move {
println!("inside tokio");
acceptor(listener).await
})
.await
.expect("tokio should start");
println!("started ldap://127.0.0.1:12345 ...");
tokio::signal::ctrl_c().await.unwrap();
}

124
src/infra/ldap_server.rs Normal file
View File

@ -0,0 +1,124 @@
use crate::infra::configuration::Configuration;
use actix_rt::net::TcpStream;
use actix_server::Server;
use actix_service::pipeline_factory;
use anyhow::Result;
use futures_util::future::{err, ok};
use log::*;
use ldap3_server::simple::*;
use ldap3_server::LdapCodec;
pub struct LdapSession {
dn: String,
}
pub fn init(config: Configuration) -> Result<()> {
debug!("LDAP: init");
actix::run(run_ldap_server(config))?;
Ok(())
}
impl LdapSession {
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()
}
}
pub fn do_search(&mut self, lsr: &SearchRequest) -> Vec<LdapMsg> {
vec![
lsr.gen_result_entry(LdapSearchResultEntry {
dn: "cn=hello,dc=example,dc=com".to_string(),
attributes: vec![
LdapPartialAttribute {
atype: "objectClass".to_string(),
vals: vec!["cursed".to_string()],
},
LdapPartialAttribute {
atype: "cn".to_string(),
vals: vec!["hello".to_string()],
},
],
}),
lsr.gen_result_entry(LdapSearchResultEntry {
dn: "cn=world,dc=example,dc=com".to_string(),
attributes: vec![
LdapPartialAttribute {
atype: "objectClass".to_string(),
vals: vec!["cursed".to_string()],
},
LdapPartialAttribute {
atype: "cn".to_string(),
vals: vec!["world".to_string()],
},
],
}),
lsr.gen_success(),
]
}
pub fn do_whoami(&mut self, wr: &WhoamiRequest) -> LdapMsg {
wr.gen_success(format!("dn: {}", self.dn).as_str())
}
}
async fn run_ldap_server(config: Configuration) {
use futures_util::SinkExt;
use futures_util::StreamExt;
use std::convert::TryFrom;
use tokio_util::codec::{FramedRead, FramedWrite};
Server::build()
.bind("test-tcp", ("0.0.0.0", config.ldap_port), move || {
pipeline_factory(move |mut stream: TcpStream| async {
// Configure the codec etc.
let (r, w) = stream.split();
let mut reqs = FramedRead::new(r, LdapCodec);
let mut resp = FramedWrite::new(w, LdapCodec);
let mut session = LdapSession {
dn: "Anonymous".to_string(),
};
while let Some(msg) = reqs.next().await {
let server_op = match msg
.map_err(|_e| ())
.and_then(|msg| ServerOps::try_from(msg))
{
Ok(aValue) => aValue,
Err(anError) => {
let _err = resp
.send(DisconnectionNotice::gen(
LdapResultCode::Other,
"Internal Server Error",
))
.await;
let _err = resp.flush().await;
break;
}
};
}
ok::<TcpStream, ()>(stream)
})
.map_err(|err| error!("Service Error: {:?}", err))
// catch
.and_then(move |_| {
// finally
ok(())
})
})
.unwrap()
.workers(1)
.run()
.await
.unwrap();
}

View File

@ -1,4 +1,5 @@
pub mod cli; pub mod cli;
pub mod configuration; pub mod configuration;
pub mod ldap_server;
pub mod logging; pub mod logging;
pub mod tcp_server; pub mod tcp_server;

View File

@ -13,7 +13,8 @@ fn main() -> Result<()> {
debug!("CLI: {:#?}", cli_opts); debug!("CLI: {:#?}", cli_opts);
debug!("Configuration: {:#?}", config); debug!("Configuration: {:#?}", config);
infra::tcp_server::init(config)?; // infra::tcp_server::init(config)?;
infra::ldap_server::init(config)?;
info!("End."); info!("End.");
Ok(()) Ok(())