feat: Implement LDAP bind/whoami
This commit is contained in:
parent
bdb5008914
commit
b4330b37fa
19 changed files with 664 additions and 37 deletions
|
|
@ -1,26 +1,35 @@
|
|||
use ldap3_proto::LdapMsg;
|
||||
use ldap3_proto::proto::LdapOp;
|
||||
|
||||
use crate::db::{Database, DatabaseInterface};
|
||||
use crate::ldap::{LdapStream, LdapStreamError};
|
||||
use crate::ldap::{LdapClientState, LdapStream, LdapStreamError, op_bind, op_ext};
|
||||
|
||||
#[tracing::instrument(name = "ldap", skip(s, db), fields(session = %s.session))]
|
||||
pub async fn ldap_handler<D: DatabaseInterface>(mut s: LdapStream, db: Database<D>) {
|
||||
#[tracing::instrument(name = "ldap", skip(stream, db), fields(session = %stream.session))]
|
||||
pub async fn ldap_handler<D: DatabaseInterface>(mut stream: LdapStream, mut db: Database<D>) {
|
||||
tracing::info! {
|
||||
remote_addr = ?s.remote_addr,
|
||||
remote_addr = ?stream.remote_addr,
|
||||
"New client connection"
|
||||
};
|
||||
|
||||
let mut state = LdapClientState::new();
|
||||
|
||||
loop {
|
||||
match s.next().await {
|
||||
Ok(msg) => {
|
||||
if let Err(e) = ldap_handler_inner(msg).await {
|
||||
match stream.next().await {
|
||||
Ok(msg) => match ldap_handler_inner(&mut stream, msg, &mut state, &mut db).await {
|
||||
Ok(should_keep_alive) => {
|
||||
if !should_keep_alive {
|
||||
tracing::debug!("Finished connection");
|
||||
return;
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::debug!(
|
||||
reason = ?e,
|
||||
"Failed to respond"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
tracing::debug!(
|
||||
reason = ?e,
|
||||
|
|
@ -32,7 +41,53 @@ pub async fn ldap_handler<D: DatabaseInterface>(mut s: LdapStream, db: Database<
|
|||
}
|
||||
}
|
||||
|
||||
pub async fn ldap_handler_inner(msg: LdapMsg) -> Result<(), LdapStreamError> {
|
||||
/// Return true to keep the connection going, false to close it.
|
||||
#[tracing::instrument(name = "ldap-handler", skip(client_state, db, stream))]
|
||||
pub async fn ldap_handler_inner<D: DatabaseInterface>(
|
||||
stream: &mut LdapStream,
|
||||
msg: LdapMsg,
|
||||
client_state: &mut LdapClientState,
|
||||
db: &mut Database<D>,
|
||||
) -> Result<bool, LdapStreamError> {
|
||||
tracing::debug!(msg = ?msg, "Received LDAP message");
|
||||
Ok(())
|
||||
match msg {
|
||||
// Disconnect
|
||||
LdapMsg {
|
||||
msgid: _,
|
||||
op: LdapOp::UnbindRequest,
|
||||
ctrl: _,
|
||||
} => {
|
||||
client_state.unbind();
|
||||
// TODO: keep the connection open?
|
||||
Ok(true)
|
||||
}
|
||||
LdapMsg {
|
||||
msgid,
|
||||
op: LdapOp::ExtendedRequest(ler),
|
||||
ctrl: _,
|
||||
} => {
|
||||
op_ext(stream, ler, msgid, client_state).await?;
|
||||
Ok(true)
|
||||
}
|
||||
LdapMsg {
|
||||
msgid,
|
||||
op: LdapOp::BindRequest(lbr),
|
||||
ctrl: _,
|
||||
} => {
|
||||
if let Some(bound_dn) = op_bind(stream, db, lbr, msgid).await? {
|
||||
tracing::debug!("Successful bind");
|
||||
client_state.bind(bound_dn);
|
||||
Ok(true)
|
||||
} else {
|
||||
tracing::debug!("Unsuccessful bind");
|
||||
// TODO: abort connection here?
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
// Unsupported message
|
||||
_ => {
|
||||
tracing::warn!("Unsupported client message, closing connection");
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue