Skip to content

feat(auth): add LDAP/Active Directory authentication with admin UI - #38668

Open
cagriman wants to merge 1 commit into
langgenius:mainfrom
cagriman:feat/ldap-ad-authentication
Open

feat(auth): add LDAP/Active Directory authentication with admin UI#38668
cagriman wants to merge 1 commit into
langgenius:mainfrom
cagriman:feat/ldap-ad-authentication

Conversation

@cagriman

Copy link
Copy Markdown

Problem

Dify Community Edition previously supported only email+password login and OAuth/SSO options (SAML, OIDC) that require Enterprise licences. Organisations running self-hosted instances behind a corporate network had no way to authenticate users against their existing LDAP/Active Directory infrastructure without adding a separate identity proxy.

Solution

This commit introduces a first-class LDAP/AD integration for self-hosted Dify deployments that works with any RFC 4511-compliant directory server (OpenLDAP, Microsoft Active Directory, FreeIPA, etc.).

What was changed

Backend – Python / Flask

  • �pi/pyproject.toml – add ldap3>=2.9.1,<3.0.0 runtime dependency
  • �pi/models/ldap_setting.py (NEW) – LdapSetting SQLAlchemy model: stores host, port, SSL flag, service-account bind credentials (encrypted), user search base/filter, attribute mapping, and fallback flag
  • �pi/models/init.py – export LdapSetting
  • �pi/migrations/versions/2026_07_10_1140-5b1b4d5e6f7a_add_ldap_settings.py (NEW) – Alembic migration that creates the ldap_settings table
  • �pi/libs/ldap.py (NEW) – LDAPAuth helper:
    • two-phase bind: service account search → user credential bind
    • encrypt_ldap_password / decrypt_ldap_password using AES-Fernet keyed on Dify's existing SECRET_KEY
    • est_connection() for connectivity checks from the UI
      
  • �pi/controllers/console/ldap.py (NEW) – REST endpoints:
    • GET /console/api/admin/ldap-settings – read current config
    • POST /console/api/admin/ldap-settings – save / update config
    • POST /console/api/admin/ldap-settings/test – connection test
      All endpoints are protected by setup_required + login_required +
      is_admin_or_owner_required.
  • �pi/controllers/console/init.py – register the new controller
  • �pi/services/account_service.py – extend AccountService.authenticate:
    1. If an enabled LdapSetting row exists, attempt LDAP auth first.
    2. On success, auto-provision the user (create account + default
      workspace) if they are not yet in the Dify database.
    3. On failure, honour allback_to_local: fall through to the existing
      email+password path or raise immediately.

Frontend – Next.js / TypeScript

  • web/app/components/header/account-setting/constants.ts – add ACCOUNT_SETTING_TAB.LDAP = 'ldap' and include it in workspace tabs
  • web/app/components/header/account-setting/ldap-page/index.tsx (NEW) – settings form: server host/port, SSL toggle, bind DN/password, search base/filter, attribute mapping, fallback toggle, and a 'Test Connection' button that hits the backend test endpoint
  • web/app/components/header/account-setting/index.tsx – render the LDAP page and show the menu item only to workspace owners/admins
  • web/service/sso.ts – add getLDAPSettings, saveLDAPSettings, estLDAPConnection service helpers

Tests

  • �pi/tests/unit_tests/services/test_account_service_ldap.py (NEW) – five pytest scenarios covering: LDAP disabled, successful login with existing user, successful login with auto-provisioning, failed login without fallback, and failed LDAP login falling back to local auth.

Behaviour

Scenario Result
LDAP enabled, valid credentials User is authenticated and auto-provisioned if new

Security notes

  • The service-account bind password is stored encrypted (Fernet/AES-128) using a key derived from the instance's SECRET_KEY. It is never returned in plaintext through the API; GET responses mask it as ******.
  • TLS/LDAPS connections use a configurable, opt-in SSL context.
  • All admin endpoints require the caller to be a workspace owner or admin.

Breaking changes

None. The feature is opt-in: unless an admin explicitly enables LDAP in the settings page the default behaviour is completely unchanged.

Important

  1. Make sure you have read our contribution guidelines
  2. Ensure there is an associated issue and you have been assigned to it
  3. Use the correct syntax to link this PR: Fixes #<issue number>.

Summary

Screenshots

Before After
... ...

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint && make type-check (backend) and cd web && pnpm exec vp staged (frontend) to appease the lint gods

@cagriman
cagriman requested review from a team July 10, 2026 13:04
@dosubot dosubot Bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Jul 10, 2026
@github-actions github-actions Bot added the web This relates to changes on the web. label Jul 10, 2026
@dosubot dosubot Bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Jul 21, 2026
@cagriman
cagriman force-pushed the feat/ldap-ad-authentication branch from af05250 to bfb2c46 Compare July 21, 2026 09:50
## Problem

Dify Community Edition previously supported only email+password login
and OAuth/SSO options (SAML, OIDC) that require Enterprise licences.
Organisations running self-hosted instances behind a corporate network
had no way to authenticate users against their existing LDAP/Active
Directory infrastructure without adding a separate identity proxy.

## Solution

This commit introduces a first-class LDAP/AD integration for self-hosted
Dify deployments that works with any RFC 4511-compliant directory server
(OpenLDAP, Microsoft Active Directory, FreeIPA, etc.).
@cagriman
cagriman force-pushed the feat/ldap-ad-authentication branch from bfb2c46 to b54e4f3 Compare July 21, 2026 10:15
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels Jul 21, 2026
@cagriman

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files. web This relates to changes on the web.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant