Basic ldap search

This commit is contained in:
Candifloss 2026-09-24 12:03:54 +05:30
parent 2e6288e835
commit abb4c7391e
4 changed files with 80 additions and 8 deletions

1
.gitignore vendored
View File

@ -23,3 +23,4 @@ Cargo.lock
# Manually added
/scratchpad/
dprint.json

View File

@ -1,8 +1,12 @@
[workspace]
resolver = "3"
members = [
"crates/config","crates/ldap","crates/password",
"tools/lk-pswdreset", "tools/lk-search"
"crates/config",
"crates/ldap",
"crates/password",
"tools/lk-pswdreset",
"tools/lk-search",
]
[workspace.package]
@ -12,7 +16,8 @@ repository = "https://git.candifloss.cc/candifloss/ldap-kit.git"
[workspace.dependencies]
anyhow = "1.0.104"
clap = { version = "4.6.4", features = ["derive"] }
clap = { version = "4.6.7", features = ["derive"] }
ldap3 = "0.12.1"
serde = { version = "1.0.229", features = ["derive"] }
toml = "1.1.4"
tokio = { version = "1.53.1", features = ["macros", "rt-multi-thread"] }
toml = "1.1.6"

View File

@ -8,5 +8,5 @@ repository.workspace = true
[dependencies]
anyhow.workspace = true
clap.workspace = true
ldap3.workspace = true
config = { path = "../../crates/config" }
ldap3.workspace = true

View File

@ -1,3 +1,69 @@
fn main() {
println!("Hello, world!");
use anyhow::{Result, bail};
use clap::{ArgGroup, Parser};
use ldap3::{LdapConn, Scope, SearchEntry};
use config::ConnectionConfig;
#[derive(Debug, Parser)]
#[command(name = "lk-search", about = "Search an LDAP user")]
#[command(group(
ArgGroup::new("user")
.required(true)
.args(["username", "id_number"])
))]
struct Args {
/// Search by username.
#[arg(short = 'u', long = "username", value_name = "USERNAME")]
username: Option<String>,
/// Search by ID number.
#[arg(short = 'n', long = "id-number", value_name = "ID")]
id_number: Option<String>,
}
fn main() -> Result<()> {
let args = Args::parse();
let config = ConnectionConfig::load()?;
let (search_attribute, search_value) = match (&args.username, &args.id_number) {
(Some(username), None) => ("uid", username),
(None, Some(id_number)) => ("uidNumber", id_number),
_ => unreachable!(),
};
let filter = format!("({search_attribute}={search_value})");
let mut ldap = LdapConn::new(&config.ldap.url)?;
ldap.simple_bind(&config.read.bind_dn, &config.read.bind_pw)?
.success()?;
let (entries, _result) = ldap
.search(&config.ldap.base_dn, Scope::Subtree, &filter, vec!["*"])?
.success()?;
if entries.is_empty() {
bail!("User not found.");
}
if entries.len() > 1 {
bail!(
"Search returned {} entries. Expected exactly one.",
entries.len()
);
}
let entry = SearchEntry::construct(entries.into_iter().next().unwrap());
println!("DN: {}", entry.dn);
for (attribute, values) in entry.attrs {
println!("{attribute}:");
for value in values {
println!(" {value}");
}
}
Ok(())
}