Add getAttribs.py

- Get LDAP attribute values in CSV format
- usage: getAttribs [-h] (-F FILE | -v VALUES) [-k KEY] -a ATTRIBUTES [-o OUTPUT] [-d DELIMITER]
This commit is contained in:
Candifloss 2026-06-29 10:38:24 +00:00
parent 6c424bb9be
commit 6c1632bf6e

206
ldap_extra/getAttribs.py Normal file
View File

@ -0,0 +1,206 @@
#!/usr/bin/env python3
import argparse
import csv
import sys
import ldap
from ldap.filter import escape_filter_chars
# ============================================================================
# Configuration
# ============================================================================
LDAP_URI = "ldaps://ldap.example.com"
BIND_DN = "uid=admin,ou=People,dc=example,dc=com"
BIND_PW = "password"
BASE_DN = "dc=example,dc=com"
DEFAULT_KEY_ATTRIBUTE = "customStaffNo"
DEFAULT_DELIMITER = "|"
DEFAULT_OUTPUT_FILE = "/tmp/ldap_output.csv"
INFO = "[i]"
START = "[*]"
SUCCESS = "[+]"
WARN = "[!]"
ERROR = "[x]"
# ============================================================================
def read_input_file(filename):
values = []
with open(filename, "r") as f:
for line in f:
line = line.strip()
if line:
values.append(line)
return values
def ldap_connect():
conn = ldap.initialize(LDAP_URI)
conn.protocol_version = ldap.VERSION3
conn.simple_bind_s(BIND_DN, BIND_PW)
return conn
def decode(value):
if isinstance(value, bytes):
return value.decode("utf-8", errors="replace")
return str(value)
def update_progress(current, total, matched, not_found):
"""Update the progress display in-place."""
sys.stdout.write("\033[3A")
sys.stdout.write(f"\r{INFO} Progress : {current:<6} / {total}\n")
sys.stdout.write(f"\r{INFO} Entries matched : {matched:<6}\n")
sys.stdout.write(f"\r{INFO} Not found : {not_found:<6}\n")
sys.stdout.flush()
def main():
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
"-F",
"--file",
help="Input file containing one value per line",
)
group.add_argument(
"-v",
"--values",
help="Comma-separated list of search values",
)
parser.add_argument(
"-k",
"--key",
default=DEFAULT_KEY_ATTRIBUTE,
help=f"LDAP attribute used for searching (default: {DEFAULT_KEY_ATTRIBUTE})",
)
parser.add_argument(
"-a",
"--attributes",
required=True,
help="Comma-separated LDAP attributes to retrieve",
)
parser.add_argument(
"-o",
"--output",
default=DEFAULT_OUTPUT_FILE,
help=f"Output CSV file (default: {DEFAULT_OUTPUT_FILE})",
)
parser.add_argument(
"-d",
"--delimiter",
default=DEFAULT_DELIMITER,
help=f"Output CSV delimiter (default: {DEFAULT_DELIMITER})",
)
args = parser.parse_args()
attributes = [x.strip() for x in args.attributes.split(",") if x.strip()]
if args.file:
search_values = read_input_file(args.file)
else:
search_values = [
x.strip()
for x in args.values.split(",")
if x.strip()
]
total = len(search_values)
matched = 0
not_found = []
incomplete = []
print(f"{START} Fetching LDAP attributes...")
print(f"{INFO} Search key : {args.key}")
print(f"{INFO} Requested attributes: {', '.join(attributes)}")
print(f"{INFO} Input values : {total}")
print(f"{INFO} Progress : 0 / {total}")
print(f"{INFO} Entries matched : 0")
print(f"{INFO} Not found : 0")
conn = ldap_connect()
with open(args.output, "w", newline="") as csvfile:
writer = csv.writer(csvfile, delimiter=args.delimiter)
writer.writerow(attributes)
for current, value in enumerate(search_values, start=1):
flt = f"({args.key}={escape_filter_chars(value)})"
result = conn.search_s(
BASE_DN,
ldap.SCOPE_SUBTREE,
flt,
attributes,
)
if not result:
not_found.append(value)
update_progress(current, total, matched, len(not_found))
continue
matched += 1
_, entry = result[0]
row = []
missing_attribute = False
for attr in attributes:
vals = entry.get(attr)
if vals:
row.append(";".join(decode(v) for v in vals))
else:
row.append("")
missing_attribute = True
if missing_attribute:
incomplete.append(value)
writer.writerow(row)
update_progress(current, total, matched, len(not_found))
conn.unbind_s()
print()
if not_found:
print(f"{WARN} Missing entries")
print(f" {args.key}: {', '.join(not_found)}")
print()
if incomplete:
print(f"{WARN} Incomplete entries")
print(" Missing one or more requested attributes:")
print(f" {args.key}: {', '.join(incomplete)}")
print()
print(f"{SUCCESS} Output written to {args.output}")
if __name__ == "__main__":
main()