Kerberos auth, StartTLS, channel binding, --debug, Python 3.13 fixes#86
Open
bandrel wants to merge 30 commits into
Open
Kerberos auth, StartTLS, channel binding, --debug, Python 3.13 fixes#86bandrel wants to merge 30 commits into
bandrel wants to merge 30 commits into
Conversation
Design spec for ccache-only Kerberos authentication via impacket, plus LDAP signing fix for strongerAuthRequired on hardened DCs, and StartTLS support for environments without LDAPS. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Nine-task TDD plan covering auth refactor, NTLM sign/seal fix, SIMPLE error improvement, TLS verify flag, StartTLS, Kerberos CLI, Kerberos bind via impacket+raw SASL, and README updates. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
No behavior change. Moves NTLM/SIMPLE bind logic out of main() into build_connection(args). Groundwork for Kerberos support and LDAP signing fixes.
Adds a regression guard verifying that build_connection passes no user, password, or authentication kwargs to Connection when args.user is None. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Modern AD DCs reject unsigned binds on plain LDAP with strongerAuthRequired (code 8). NTLM session_security=ENCRYPT negotiates sign/seal and is a no-op over TLS. Note: ldap3 2.x (latest 2.9.1) does not export ENCRYPT; the constant is defined locally in auth.py as a sentinel. When ldap3 gains native ENCRYPT support this can be swapped to a direct import.
…irement" This reverts commit b909be1.
ldap3 2.9.1 has no NTLM signing support (no ENCRYPT constant, no session_security kwarg on Connection). Verified via introspection. Implementing it would require a library swap or heavy monkey-patching, both out of scope. Task 3 is skipped; Task 4 gains an NTLM-specific error message pointing users at the three working signing paths: Kerberos, LDAPS, StartTLS. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
For SIMPLE and NTLM binds rejected with code 8 on hardened DCs, surface an auth-type-specific message pointing at Kerberos / LDAPS / StartTLS — the three signing paths that actually work. ldap3 2.9.1 does not support NTLM sign/seal, so we guide users to working alternatives instead of dumping the raw LDAP result dict.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduces _build_server() helper and --no-tls-verify escape hatch for self-signed DC certificates. Extracts argparse into _build_parser() so CLI-level tests can exercise it without invoking main().
…d test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Supports environments where port 636 is firewalled. Argparse rejects --start-tls with ldaps:// URLs via _validate_args. Bind helpers now explicitly open() -> maybe start_tls() -> bind().
Previously _open_and_maybe_start_tls silently discarded the boolean return of Connection.open() and Connection.start_tls(). A failed StartTLS upgrade would fall through to a plaintext bind — a silent downgrade of the very security guarantee the user requested. Both return values are now checked and surfaced as AuthError.
…tions Adds BloodHound.py-style authentication flags including Kerberos (-k), hashes (--hashes), AES key (-aesKey), auth method (--auth-method), domain, and LDAP channel binding. Replaces -at/--authtype with --auth-method that defaults to 'auto' for Kerberos-first behavior. Changes -u/--user to -u/--username for consistency with impacket conventions. Adds -no-pass flag for non-interactive auth scenarios. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Reject -k with --auth-method ntlm (incompatible) - Reject -k without username (anonymous Kerberos unsupported) - Reject --auth-method kerberos without username - Imply --auth-method kerberos when -k is passed with valid username Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds 5 methods to ADAuthentication class: - _kerberos_usable() checks if Kerberos credentials are available - _kerberos_forced() returns True when ccache is in use (no fallback) - _ensure_tgt() populates self.tgt from ccache or AS-REQ - _ntlm_login() formats the domain\username string for NTLM bind - authenticate() orchestrates the full auth flow: Kerberos first, then NTLM/anonymous fallback with proper error handling and channel binding Implements Kerberos-first strategy with graceful fallback to NTLM when auto mode is used. Validates auth_method to prevent unexpected code paths. Adds 9 tests covering: - Kerberos usability checks (username, password, ccache paths) - Forced vs optional fallback logic - Anonymous, NTLM, and Kerberos bind paths - Channel binding validation and error messages - Safety check for auth_method='kerberos' fallthrough All 50 tests pass (29 auth + 21 CLI). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…mpt helper - Rewrite auth.py: ADAuthentication wires into build_connection(args), UPN username parsing, down-level rejection, FQDN enforcement for Kerberos - Extract _prompt_password_if_needed() from main(); -k and -no-pass suppress getpass - Replace old test_auth.py with 13 new tests covering dispatcher surface - Add 3 test_cli.py tests for password prompt logic - All 67 tests pass; entry point imports verified Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mainline ldap3 lacks NTLM sign/seal and channel binding support, both needed against modern AD with LDAP signing required. Python 3.13's hashlib also dropped MD4, which ldap3's NTLM path needs via Crypto.Hash.MD4 from pycryptodome. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The --start-tls CLI flag existed but was never honored. Plumb it through ADAuthentication and run StartTLS on the open socket before bind, for both Kerberos and NTLM paths. ldap_kerberos previously called connection.open() unconditionally; ldap3 treats that as a re-open and tears down the existing socket, which would discard our StartTLS wrap. Guard it with `if connection.closed`. Also surface the swallowed AuthError detail when Kerberos falls back to NTLM, to make misconfigurations debuggable. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Configures root logging at DEBUG and bumps ldap3's library log detail to EXTENDED so the auth flow (Kerberos referrals, NTLM negotiation, TLS) can be traced when binds misbehave. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Kerberos authentication and several closely related auth/UX features needed to operate against modern AD where NTLM is disabled or LDAP signing is enforced. Implements the work proposed in #82, #83, #84, #85.
Authentication
-k,-aesKey,--auth-method,--domain) — TGT fromKRB5CCNAME, AES key auth, cross-realm referral walk, graceful NTLM fallback underauto. Ported (with pruning) from BloodHound.py's auth module — fixes Add Kerberos authentication support (-k, ccache, AES key, channel binding) #82--ldap-channel-binding) — RFC 5929tls-server-end-pointfor both NTLM and Kerberos GSS — part of Add Kerberos authentication support (-k, ccache, AES key, channel binding) #82TLS_CHANNEL_BINDING) and addspycryptodome(Python 3.13 dropped MD4 fromhashlib) — fixes NTLM bind broken on Python 3.13 (MD4 removed) and against signing-required DCs #85CLI / UX
--start-tls— upgrade plain LDAP to TLS before bind; composes with--no-tls-verifyand all auth methods. Includes a guard in the Kerberos path soConnection.open()doesn't tear down the StartTLS-wrapped socket — fixes Add --start-tls to upgrade plain LDAP to TLS before bind #83--debug— verbose auth flow + ldap3EXTENDEDlogging — fixes Add --debug for verbose auth + ldap3 logging #84Dependencies
ldap3is pinned to the ly4k fork inpyproject.toml. Open to switching to a soft dependency / runtime check if you'd prefer not to vendor a fork by default — happy to rework however you'd like.Test plan
-kagainst a DC using a TGT fromKRB5CCNAME-kcross-realm (user in trusted realm)-aesKeyAES auth--auth-method ntlmagainst a DC requiring signing (with ly4k fork)--start-tlswith NTLM and with Kerberos--ldap-channel-bindingagainst ldaps:// and StartTLS--debugproduces ldap3 EXTENDED logs🤖 Generated with Claude Code