mirror of
https://github.com/nitnelave/lldap.git
synced 2023-04-12 14:25:13 +00:00
server: Implement LDAPS support
This commit is contained in:
parent
6b6f11db1b
commit
f689458aa2
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -1917,6 +1917,7 @@ dependencies = [
|
|||||||
"lldap_auth",
|
"lldap_auth",
|
||||||
"log",
|
"log",
|
||||||
"mockall",
|
"mockall",
|
||||||
|
"native-tls",
|
||||||
"opaque-ke",
|
"opaque-ke",
|
||||||
"openssl-sys",
|
"openssl-sys",
|
||||||
"orion",
|
"orion",
|
||||||
@ -1931,6 +1932,7 @@ dependencies = [
|
|||||||
"thiserror",
|
"thiserror",
|
||||||
"time 0.2.27",
|
"time 0.2.27",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-native-tls",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -2150,9 +2152,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.8"
|
version = "0.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d"
|
checksum = "fd7e2f3618557f980e0b17e8856252eee3c97fa12c54dff0ca290fb6266ca4a9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -30,6 +30,7 @@ ldap3_server = ">=0.1.9"
|
|||||||
lldap_auth = { path = "../auth" }
|
lldap_auth = { path = "../auth" }
|
||||||
log = "*"
|
log = "*"
|
||||||
orion = "0.16"
|
orion = "0.16"
|
||||||
|
native-tls = "0.2.10"
|
||||||
serde = "*"
|
serde = "*"
|
||||||
serde_json = "1"
|
serde_json = "1"
|
||||||
sha2 = "0.9"
|
sha2 = "0.9"
|
||||||
@ -37,6 +38,7 @@ sqlx-core = "=0.5.1"
|
|||||||
thiserror = "*"
|
thiserror = "*"
|
||||||
time = "0.2"
|
time = "0.2"
|
||||||
tokio = { version = "1.2.0", features = ["full"] }
|
tokio = { version = "1.2.0", features = ["full"] }
|
||||||
|
tokio-native-tls = "0.3"
|
||||||
tokio-util = "0.6.3"
|
tokio-util = "0.6.3"
|
||||||
tokio-stream = "*"
|
tokio-stream = "*"
|
||||||
tracing = "*"
|
tracing = "*"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
domain::{
|
domain::{
|
||||||
handler::{BackendHandler, LoginHandler},
|
handler::{BackendHandler, LoginHandler, UserId},
|
||||||
opaque_handler::OpaqueHandler,
|
opaque_handler::OpaqueHandler,
|
||||||
},
|
},
|
||||||
infra::{configuration::Configuration, ldap_handler::LdapHandler},
|
infra::{configuration::Configuration, ldap_handler::LdapHandler},
|
||||||
@ -9,19 +9,21 @@ use actix_rt::net::TcpStream;
|
|||||||
use actix_server::ServerBuilder;
|
use actix_server::ServerBuilder;
|
||||||
use actix_service::{fn_service, ServiceFactoryExt};
|
use actix_service::{fn_service, ServiceFactoryExt};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use futures_util::future::ok;
|
|
||||||
use ldap3_server::{proto::LdapMsg, LdapCodec};
|
use ldap3_server::{proto::LdapMsg, LdapCodec};
|
||||||
use log::*;
|
use log::*;
|
||||||
use tokio::net::tcp::WriteHalf;
|
use native_tls::{Identity, TlsAcceptor};
|
||||||
|
use tokio_native_tls::TlsAcceptor as NativeTlsAcceptor;
|
||||||
use tokio_util::codec::{FramedRead, FramedWrite};
|
use tokio_util::codec::{FramedRead, FramedWrite};
|
||||||
|
|
||||||
async fn handle_incoming_message<Backend>(
|
async fn handle_incoming_message<Backend, Writer>(
|
||||||
msg: Result<LdapMsg, std::io::Error>,
|
msg: Result<LdapMsg, std::io::Error>,
|
||||||
resp: &mut FramedWrite<WriteHalf<'_>, LdapCodec>,
|
resp: &mut Writer,
|
||||||
session: &mut LdapHandler<Backend>,
|
session: &mut LdapHandler<Backend>,
|
||||||
) -> Result<bool>
|
) -> Result<bool>
|
||||||
where
|
where
|
||||||
Backend: BackendHandler + LoginHandler + OpaqueHandler,
|
Backend: BackendHandler + LoginHandler + OpaqueHandler,
|
||||||
|
Writer: futures_util::Sink<LdapMsg> + Unpin,
|
||||||
|
<Writer as futures_util::Sink<LdapMsg>>::Error: std::error::Error + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
use futures_util::SinkExt;
|
use futures_util::SinkExt;
|
||||||
let msg = msg.context("while receiving LDAP op")?;
|
let msg = msg.context("while receiving LDAP op")?;
|
||||||
@ -51,6 +53,56 @@ where
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_file_as_byte_vec(filename: &str) -> Result<Vec<u8>> {
|
||||||
|
(|| -> Result<Vec<u8>> {
|
||||||
|
use std::fs::{metadata, File};
|
||||||
|
use std::io::Read;
|
||||||
|
let mut f = File::open(&filename).context("file not found")?;
|
||||||
|
let metadata = metadata(&filename).context("unable to read metadata")?;
|
||||||
|
let mut buffer = vec![0; metadata.len() as usize];
|
||||||
|
f.read(&mut buffer).context("buffer overflow")?;
|
||||||
|
Ok(buffer)
|
||||||
|
})()
|
||||||
|
.context(format!("while reading file {}", filename))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_ldap_stream<Stream, Backend>(
|
||||||
|
stream: Stream,
|
||||||
|
backend_handler: Backend,
|
||||||
|
ldap_base_dn: String,
|
||||||
|
ldap_user_dn: UserId,
|
||||||
|
) -> Result<Stream>
|
||||||
|
where
|
||||||
|
Backend: BackendHandler + LoginHandler + OpaqueHandler + 'static,
|
||||||
|
Stream: tokio::io::AsyncRead + tokio::io::AsyncWrite,
|
||||||
|
{
|
||||||
|
use tokio_stream::StreamExt;
|
||||||
|
let (r, w) = tokio::io::split(stream);
|
||||||
|
// Configure the codec etc.
|
||||||
|
let mut requests = FramedRead::new(r, LdapCodec);
|
||||||
|
let mut resp = FramedWrite::new(w, LdapCodec);
|
||||||
|
|
||||||
|
let mut session = LdapHandler::new(backend_handler, ldap_base_dn, ldap_user_dn);
|
||||||
|
|
||||||
|
while let Some(msg) = requests.next().await {
|
||||||
|
if !handle_incoming_message(msg, &mut resp, &mut session)
|
||||||
|
.await
|
||||||
|
.context("while handling incoming messages")?
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(requests.into_inner().unsplit(resp.into_inner()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_tls_acceptor(config: &Configuration) -> Result<NativeTlsAcceptor> {
|
||||||
|
// Load TLS key and cert files
|
||||||
|
let cert_file = get_file_as_byte_vec(&config.ldaps_options.cert_file)?;
|
||||||
|
let key_file = get_file_as_byte_vec(&config.ldaps_options.key_file)?;
|
||||||
|
let identity = Identity::from_pkcs8(&cert_file, &key_file)?;
|
||||||
|
Ok(TlsAcceptor::new(identity)?.into())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build_ldap_server<Backend>(
|
pub fn build_ldap_server<Backend>(
|
||||||
config: &Configuration,
|
config: &Configuration,
|
||||||
backend_handler: Backend,
|
backend_handler: Backend,
|
||||||
@ -59,44 +111,51 @@ pub fn build_ldap_server<Backend>(
|
|||||||
where
|
where
|
||||||
Backend: BackendHandler + LoginHandler + OpaqueHandler + 'static,
|
Backend: BackendHandler + LoginHandler + OpaqueHandler + 'static,
|
||||||
{
|
{
|
||||||
use futures_util::StreamExt;
|
let context = (
|
||||||
|
backend_handler,
|
||||||
|
config.ldap_base_dn.clone(),
|
||||||
|
config.ldap_user_dn.clone(),
|
||||||
|
);
|
||||||
|
|
||||||
let ldap_base_dn = config.ldap_base_dn.clone();
|
let tls_context = (
|
||||||
let ldap_user_dn = config.ldap_user_dn.clone();
|
context.clone(),
|
||||||
server_builder
|
get_tls_acceptor(config).context("while setting up the SSL certificate")?,
|
||||||
.bind("ldap", ("0.0.0.0", config.ldap_port), move || {
|
);
|
||||||
let backend_handler = backend_handler.clone();
|
|
||||||
let ldap_base_dn = ldap_base_dn.clone();
|
|
||||||
let ldap_user_dn = ldap_user_dn.clone();
|
|
||||||
fn_service(move |mut stream: TcpStream| {
|
|
||||||
let backend_handler = backend_handler.clone();
|
|
||||||
let ldap_base_dn = ldap_base_dn.clone();
|
|
||||||
let ldap_user_dn = ldap_user_dn.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 = LdapHandler::new(backend_handler, ldap_base_dn, ldap_user_dn);
|
let binder = move || {
|
||||||
|
let context = context.clone();
|
||||||
while let Some(msg) = requests.next().await {
|
fn_service(move |stream: TcpStream| {
|
||||||
if !handle_incoming_message(msg, &mut resp, &mut session)
|
let context = context.clone();
|
||||||
.await
|
async move {
|
||||||
.context("while handling incoming messages")?
|
let (handler, base_dn, user_dn) = context;
|
||||||
{
|
handle_ldap_stream(stream, handler, base_dn, user_dn).await
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(stream)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map_err(|err: anyhow::Error| error!("Service Error: {:#}", err))
|
|
||||||
.and_then(move |_| {
|
|
||||||
// finally
|
|
||||||
ok(())
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.with_context(|| format!("while binding to the port {}", config.ldap_port))
|
.map_err(|err: anyhow::Error| error!("[LDAP] Service Error: {:#}", err))
|
||||||
|
};
|
||||||
|
|
||||||
|
let tls_binder = move || {
|
||||||
|
let tls_context = tls_context.clone();
|
||||||
|
fn_service(move |stream: TcpStream| {
|
||||||
|
let tls_context = tls_context.clone();
|
||||||
|
async move {
|
||||||
|
let ((handler, base_dn, user_dn), tls_acceptor) = tls_context;
|
||||||
|
let tls_stream = tls_acceptor.clone().accept(stream).await?;
|
||||||
|
handle_ldap_stream(tls_stream, handler, base_dn, user_dn).await
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.map_err(|err: anyhow::Error| error!("[LDAPS] Service Error: {:#}", err))
|
||||||
|
};
|
||||||
|
|
||||||
|
let server_builder = server_builder
|
||||||
|
.bind("ldap", ("0.0.0.0", config.ldap_port), binder)
|
||||||
|
.with_context(|| format!("while binding to the port {}", config.ldap_port));
|
||||||
|
if config.ldaps_options.enabled {
|
||||||
|
server_builder.and_then(|s| {
|
||||||
|
s.bind("ldaps", ("0.0.0.0", config.ldaps_options.port), tls_binder)
|
||||||
|
.with_context(|| format!("while binding to the port {}", config.ldaps_options.port))
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
server_builder
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user