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})
  # LDAPGate requires at least one authorization rule by default:
  group_dn: CN=app-users,CN=Users,DC=example,DC=com  # restrict by group
  allowed_users:                                      # or restrict by 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 ...

⚠️ Warning: tls_validate: NONE disables all TLS certificate validation and makes you vulnerable to man-in-the-middle attacks. Whenever possible, use tls_ca_cert_file to trust your internal CA instead.

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.

Successful Basic auth checks are cached briefly in memory by default (proxy.basic_auth_cache_ttl: 60) so chatty WebDAV clients like macOS Finder do not force a fresh LDAP bind for every metadata request. Set it to 0 to disable the cache.

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.7.tar.gz (206.2 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.7-py3-none-any.whl (136.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: ldapgate-0.1.7.tar.gz
  • Upload date:
  • Size: 206.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.20 {"installer":{"name":"uv","version":"0.11.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","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.7.tar.gz
Algorithm Hash digest
SHA256 0a942498db9cd586703f4db276d7efb21633a88e819b1712f4102220a40397da
MD5 f63ce39edab838f17d4e7dedd36118f3
BLAKE2b-256 a141576ebc954deded97e61745155db21c4c8c7e0e5945d1844e5a256f90461d

See more details on using hashes here.

File details

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

File metadata

  • Download URL: ldapgate-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 136.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.20 {"installer":{"name":"uv","version":"0.11.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","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.7-py3-none-any.whl
Algorithm Hash digest
SHA256 e4cd7d8704ae533bebe27797fd30dfb0318d160ff97fc03f775b92b538046a8e
MD5 efca5ff2c44631364a492d001ff1f248
BLAKE2b-256 b9e4babfad18c6d9774cbdc2e6ac86c83cf2148f96e7ef5fda327493d1f5cc78

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