2021-03-06 22:39:34 +00:00
|
|
|
use crate::infra::configuration::Configuration;
|
|
|
|
use actix_rt::net::TcpStream;
|
2021-03-07 11:36:12 +00:00
|
|
|
use actix_server::ServerBuilder;
|
|
|
|
use actix_service::{fn_service, pipeline_factory};
|
2021-03-06 22:39:34 +00:00
|
|
|
use anyhow::Result;
|
2021-03-07 11:36:12 +00:00
|
|
|
use futures_util::future::ok;
|
2021-03-06 22:39:34 +00:00
|
|
|
use log::*;
|
|
|
|
|
|
|
|
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())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-07 11:36:12 +00:00
|
|
|
pub fn build_ldap_server(
|
|
|
|
config: &Configuration,
|
|
|
|
server_builder: ServerBuilder,
|
|
|
|
) -> Result<ServerBuilder> {
|
2021-03-06 22:39:34 +00:00
|
|
|
use futures_util::SinkExt;
|
|
|
|
use futures_util::StreamExt;
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
use tokio_util::codec::{FramedRead, FramedWrite};
|
|
|
|
|
2021-03-07 11:36:12 +00:00
|
|
|
Ok(
|
|
|
|
server_builder.bind("ldap", ("0.0.0.0", config.ldap_port), move || {
|
|
|
|
pipeline_factory(fn_service(move |mut stream: TcpStream| async {
|
2021-03-06 22:39:34 +00:00
|
|
|
// 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))
|
|
|
|
{
|
2021-03-07 11:36:12 +00:00
|
|
|
Ok(a_value) => a_value,
|
|
|
|
Err(an_error) => {
|
2021-03-06 22:39:34 +00:00
|
|
|
let _err = resp
|
|
|
|
.send(DisconnectionNotice::gen(
|
|
|
|
LdapResultCode::Other,
|
|
|
|
"Internal Server Error",
|
|
|
|
))
|
|
|
|
.await;
|
|
|
|
let _err = resp.flush().await;
|
2021-03-07 11:36:12 +00:00
|
|
|
return Err(format!("Internal server error: {:?}", an_error));
|
2021-03-06 22:39:34 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2021-03-07 11:36:12 +00:00
|
|
|
Ok(stream)
|
|
|
|
}))
|
2021-03-06 22:39:34 +00:00
|
|
|
.map_err(|err| error!("Service Error: {:?}", err))
|
|
|
|
// catch
|
|
|
|
.and_then(move |_| {
|
|
|
|
// finally
|
|
|
|
ok(())
|
|
|
|
})
|
2021-03-07 11:36:12 +00:00
|
|
|
})?,
|
|
|
|
)
|
2021-03-06 22:39:34 +00:00
|
|
|
}
|