Split lk-search/src/main.rs
- Module for arg-parsing - New crate for ldap client code - Introduce man-page generation
This commit is contained in:
parent
e7d5da4678
commit
76eb96a96f
@ -21,3 +21,4 @@ ldap3 = "0.12.1"
|
||||
serde = { version = "1.0.229", features = ["derive"] }
|
||||
tokio = { version = "1.53.1", features = ["macros", "rt-multi-thread"] }
|
||||
toml = "1.1.6"
|
||||
clap_mangen = "0.3.3"
|
||||
@ -1 +1,39 @@
|
||||
use anyhow::Result;
|
||||
use ldap3::{LdapConn, Scope, SearchEntry};
|
||||
|
||||
use config::ConnectionConfig;
|
||||
|
||||
/// LDAP client.
|
||||
pub struct LdapClient {
|
||||
connection: LdapConn,
|
||||
}
|
||||
|
||||
impl LdapClient {
|
||||
/// Connect to the LDAP server using the read credentials.
|
||||
pub fn connect(config: &ConnectionConfig) -> Result<Self> {
|
||||
let mut connection = LdapConn::new(&config.ldap.url)?;
|
||||
|
||||
connection
|
||||
.simple_bind(&config.read.bind_dn, &config.read.bind_pw)?
|
||||
.success()?;
|
||||
|
||||
Ok(Self { connection })
|
||||
}
|
||||
|
||||
/// Search the LDAP directory.
|
||||
///
|
||||
/// Returns the matching entries as `ldap3::SearchEntry` values.
|
||||
pub fn search(
|
||||
&mut self,
|
||||
base_dn: &str,
|
||||
filter: &str,
|
||||
attributes: Vec<&str>,
|
||||
) -> Result<Vec<SearchEntry>> {
|
||||
let (entries, _) = self
|
||||
.connection
|
||||
.search(base_dn, Scope::Subtree, filter, attributes)?
|
||||
.success()?;
|
||||
|
||||
Ok(entries.into_iter().map(SearchEntry::construct).collect())
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
mod client;
|
||||
mod user;
|
||||
|
||||
//pub use client::LdapClient;
|
||||
pub use user::User;
|
||||
pub use client::LdapClient;
|
||||
|
||||
@ -9,4 +9,9 @@ repository.workspace = true
|
||||
anyhow.workspace = true
|
||||
clap.workspace = true
|
||||
config = { path = "../../crates/config" }
|
||||
ldap = { path = "../../crates/ldap" }
|
||||
ldap3.workspace = true
|
||||
|
||||
[build-dependencies]
|
||||
clap.workspace = true
|
||||
clap_mangen.workspace = true
|
||||
23
tools/lk-search/build.rs
Normal file
23
tools/lk-search/build.rs
Normal file
@ -0,0 +1,23 @@
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::CommandFactory;
|
||||
use clap_mangen::Man;
|
||||
|
||||
#[path = "src/args.rs"]
|
||||
mod args;
|
||||
|
||||
fn main() -> std::io::Result<()> {
|
||||
let out_dir = PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
|
||||
let command = args::Args::command();
|
||||
let man = Man::new(command);
|
||||
|
||||
let mut output = Vec::new();
|
||||
man.render(&mut output)?;
|
||||
|
||||
fs::write(out_dir.join("lk-search.1"), output)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
18
tools/lk-search/src/args.rs
Normal file
18
tools/lk-search/src/args.rs
Normal file
@ -0,0 +1,18 @@
|
||||
use clap::{ArgGroup, Parser};
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "lk-search", about = "Search an LDAP directory")]
|
||||
#[command(group(
|
||||
ArgGroup::new("search")
|
||||
.required(true)
|
||||
.args(["username", "id"])
|
||||
))]
|
||||
pub struct Args {
|
||||
/// Search by username.
|
||||
#[arg(short = 'u', long = "username", value_name = "USERNAME")]
|
||||
pub username: Option<String>,
|
||||
|
||||
/// Search by identifier.
|
||||
#[arg(short = 'i', long = "id", value_name = "ID")]
|
||||
pub id: Option<String>,
|
||||
}
|
||||
@ -1,49 +1,31 @@
|
||||
mod args;
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use clap::{ArgGroup, Parser};
|
||||
use ldap3::{LdapConn, Scope, SearchEntry};
|
||||
use clap::Parser;
|
||||
|
||||
use config::ConnectionConfig;
|
||||
use ldap::LdapClient;
|
||||
|
||||
#[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>,
|
||||
}
|
||||
use args::Args;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = Args::parse();
|
||||
let config = ConnectionConfig::load()?;
|
||||
|
||||
let (search_attribute, search_value) = match (&args.username, &args.id_number) {
|
||||
let (search_attribute, search_value) = match (&args.username, &args.id) {
|
||||
(Some(username), None) => ("uid", username),
|
||||
(None, Some(id_number)) => ("uidNumber", id_number),
|
||||
(None, Some(id)) => ("uidNumber", id),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let filter = format!("({search_attribute}={search_value})");
|
||||
|
||||
let mut ldap = LdapConn::new(&config.ldap.url)?;
|
||||
let mut ldap = LdapClient::connect(&config)?;
|
||||
|
||||
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()?;
|
||||
let entries = ldap.search(&config.ldap.base_dn, &filter, vec!["*"])?;
|
||||
|
||||
if entries.is_empty() {
|
||||
bail!("User not found.");
|
||||
bail!("No matching entries found.");
|
||||
}
|
||||
|
||||
if entries.len() > 1 {
|
||||
@ -53,11 +35,11 @@ fn main() -> Result<()> {
|
||||
);
|
||||
}
|
||||
|
||||
let entry = SearchEntry::construct(entries.into_iter().next().unwrap());
|
||||
let entry = &entries[0];
|
||||
|
||||
println!("DN: {}", entry.dn);
|
||||
|
||||
for (attribute, values) in entry.attrs {
|
||||
for (attribute, values) in &entry.attrs {
|
||||
println!("{attribute}:");
|
||||
|
||||
for value in values {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user