Skip to main content

Lightweight LDAP/AD authentication proxy and FastAPI middleware

Project description

LDAPGate

LDAPGate

Lightweight LDAP/AD authentication gateway for Python web apps. Install it, configure it, done.

Features

  • Two deployment modes — standalone reverse proxy or drop-in FastAPI middleware
  • WebDAV + browser in one — browsers get a login form; WebDAV clients (Windows, macOS Finder, curl) get a Basic auth challenge — same endpoint, no extra config
  • Pure Python LDAP — no OS-level libs required, uses ldap3
  • Signed cookie sessions — stateless, no server-side session storage
  • OpenLDAP and Active Directoryuid= and sAMAccountName= out of the box
  • Optional group gating — restrict access to members of a specific LDAP group
  • Header injection — injects X-Forwarded-User for downstream apps
  • Bundled login form — responsive, dark/light mode, customisable, works air-gapped

Install

pip install ldapgate

Config file

Both modes share the same ldapgate.yaml:

ldap:
  url: ldaps://dc.example.com:636
  bind_dn: CN=svc,CN=Users,DC=example,DC=com
  bind_password: secret
  base_dn: DC=example,DC=com
  user_filter: "(sAMAccountName={username})"         # AD; OpenLDAP: (uid={username})
  group_dn: CN=app-users,CN=Users,DC=example,DC=com  # optional — restrict by group
  allowed_users:                                      # optional — local allowlist
    - alice
    - bob
  timeout: 10
  tls_validate: REQUIRED                             # NONE | OPTIONAL | REQUIRED
  tls_ca_cert_file: /etc/ssl/certs/internal-ca.pem  # optional — custom CA bundle
  tls_client_cert_file: /etc/ssl/certs/client.pem   # optional — mutual TLS client cert
  tls_client_key_file: /etc/ssl/private/client.key  # optional — mutual TLS client key

proxy:
  listen_host: 0.0.0.0
  listen_port: 9000
  backend_url: http://localhost:8080
  secret_key: change-me-to-something-random
  session_ttl: 3600
  user_header: X-Forwarded-User
  login_path: /_auth/login
  logout_path: /_auth/logout
  app_name: MyApp
  secure_cookies: false                              # set true when behind HTTPS

All settings can also be provided via environment variables using __ as a separator — e.g. LDAP__URL, PROXY__SECRET_KEY.

Corporate / Active Directory setup

For corp environments with internal CAs where cert validation isn't feasible:

ldap:
  url: ldaps://dc.example.com:636
  tls_validate: NONE
  # ... other settings ...

For plain LDAP with STARTTLS:

ldap:
  url: ldap://dc.example.com:389
  use_starttls: true

Mode 1 — Standalone Reverse Proxy

Run ldapgate as a standalone process in front of any app.

Browser / WebDAV client → ldapgate :9000 → backend app :8080
ldapgate serve --config ldapgate.yaml

All traffic is intercepted by ldapgate before reaching the backend. Authenticated requests are forwarded with the X-Forwarded-User header set to the verified username. Apps can point their logout link at the configured logout_path (default /_auth/logout) to clear the session.

WebDAV clients receive a 401 WWW-Authenticate: Basic challenge automatically and authenticate per-request via HTTP Basic auth — no session cookie needed.


Mode 2 — FastAPI Middleware

Drop ldapgate auth directly into an existing FastAPI app — no separate process.

from fastapi import FastAPI
from ldapgate.config import load_config
from ldapgate.middleware import add_ldap_auth

app = FastAPI()
config = load_config("ldapgate.yaml")
add_ldap_auth(app, config)

@app.get("/api/data")
async def data(request):
    return {"user": request.state.user}  # authenticated username

add_ldap_auth registers the login/logout routes and attaches the middleware in one call. The authenticated username is available as request.state.user and is also injected as the configured user_header into the request headers.

WebDAV with middleware

The middleware handles both browser and WebDAV clients on the same app instance:

Client Auth flow
Browser Redirected to login form → session cookie
WebDAV (Windows, macOS Finder, curl) 401 WWW-Authenticate: Basic challenge → Basic auth per-request

No extra routes or config needed — if a request arrives without a session cookie and without Accept: text/html, the middleware issues a 401 with a WWW-Authenticate: Basic header. The client sends credentials, the middleware validates against LDAP, and the request proceeds.

allowed_users and group_dn apply to both flows — a user blocked by those settings is rejected regardless of whether they authenticated via cookie or Basic auth.

Example — xwing file server with WebDAV:

from fastapi import FastAPI
from ldapgate.config import load_config
from ldapgate.middleware import add_ldap_auth
from xwing.app import create_app
from xwing.config import Settings

xwing_settings = Settings(root_dir="/srv/files", users_config="users.yaml")
app = create_app(xwing_settings)

ldap_config = load_config("ldapgate.yaml")
add_ldap_auth(app, ldap_config)

Windows users can now map http://your-server:8989/ as a network drive:

net use Z: http://your-server:8989/ /user:alice /persistent:yes

macOS Finder: Go → Connect to Server (⌘K) → http://your-server:8989/


CLI reference

ldapgate serve [OPTIONS]

  --config PATH     Path to ldapgate.yaml (reads env vars if omitted)
  --host TEXT       Override listen host
  --port INTEGER    Override listen port
  --backend TEXT    Override backend URL
  --reload          Enable auto-reload (dev only)

Development

Requires uv.

git clone https://github.com/anudeepd/ldapgate
cd ldapgate
uv sync
uv run pytest

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ldapgate-0.1.4.tar.gz (862.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ldapgate-0.1.4-py3-none-any.whl (114.4 kB view details)

Uploaded Python 3

File details

Details for the file ldapgate-0.1.4.tar.gz.

File metadata

  • Download URL: ldapgate-0.1.4.tar.gz
  • Upload date:
  • Size: 862.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ldapgate-0.1.4.tar.gz
Algorithm Hash digest
SHA256 f1467de1c8e1e7e9c8f9664b9f7989b0583682fd2ad8eadd107a527e7e48537c
MD5 cc6f36c1300df4da270aa4ab966bfc95
BLAKE2b-256 89121227c4ede67b1b81d59c80463f8d1bc5f50dcac84003fb0b41d62b09971e

See more details on using hashes here.

File details

Details for the file ldapgate-0.1.4-py3-none-any.whl.

File metadata

  • Download URL: ldapgate-0.1.4-py3-none-any.whl
  • Upload date:
  • Size: 114.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for ldapgate-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 918735cd12f5bf8618aa07ebda786c7492cba19eeebda916babbf691e6516285
MD5 701d5ec6c4694cd041f8c454b1361d60
BLAKE2b-256 89074c26a6e2b5fa4f3515492754e99c924950a1bc67d052fb73a9973043f263

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page