Many legacy and on-premises applications still authenticate users by binding to the directory over LDAP, which means every one of them handles passwords, holds a bind service account and sits outside the MFA and conditional access policies applied at the identity provider. SAML and OpenID Connect move authentication to the identity provider and hand the application a signed assertion or token instead. This guide is about the choice that matters most for those applications: keep the LDAP bind and harden it, or front the application with federation. It covers threat models for each option, the specific LDAP controls (LDAPS, signing, channel binding, bind account scoping), when to put a federation layer in front, and a worked migration scenario. The comparison between SAML and OIDC themselves is covered in the SAML vs OIDC Guide; this page links to it rather than repeating it. It is written for identity architects, application owners and directory administrators.
Key takeaways
- LDAP is a directory access protocol, not a federation protocol. An LDAP bind proves a password to one directory server for one connection; SAML and OIDC give the application a signed statement it can verify without ever seeing the password.
- Every LDAP-authenticating app is a password collector. The user types the directory password into the application, so a compromised app or a cleartext bind exposes the real credential, and no phishing-resistant MFA can sit in that path.
- If an LDAP bind must stay, harden the transport and the bind account. Require LDAPS or StartTLS with certificate validation, enforce signing and channel binding on Active Directory, and scope the bind service account to read only what the app needs.
- Front with federation when the app supports it or a proxy can. Move users to SAML or OIDC at the identity provider, keep LDAP only for group lookups by a scoped service account, then remove the password from the app.
- Choose SAML or OIDC by client type, not by fashion. Browser workforce apps that only speak SAML stay on SAML; new web, mobile and API clients use OIDC with Authorization Code and PKCE. Kerberos remains the right answer for Windows integrated authentication inside the domain.
What each protocol actually does
The three are often listed together as "authentication protocols", but they solve different problems, and that difference drives every security decision below.
- LDAP (RFC 4511, Standards Track, June 2006): a protocol for reading and writing a directory. A
BindRequestcarries a protocol version, a distinguished name and an authentication choice of eithersimple(a password) orsasl(a SASL mechanism). RFC 4511 recommends servers listen on port 389; LDAP over TLS conventionally uses 636. The result of a successful bind is an authenticated connection to that directory, nothing more. - SAML 2.0: an XML federation standard. The identity provider authenticates the user and returns a signed
<Response>and<Assertion>through the browser to the service provider, which validates the signature, audience and timing and creates its own session. - OpenID Connect: an identity layer on OAuth 2.0 (Core 1.0 incorporating errata set 2, Final, December 2023). The relying party receives a signed JWT ID token and, usually, OAuth access tokens for calling APIs.
- Kerberos: the ticket protocol (port 88) that Active Directory uses for integrated Windows authentication inside a realm. It is often the best option for on-premises Windows applications and is compared with LDAP in the Kerberos vs LDAP guide.
The architectural distinction is set out in the Directory Service vs Identity Provider guide: the directory is the store of record, the identity provider is the token issuer. An application that binds to LDAP is using the store of record as its login page.
Side-by-side comparison
| Aspect | LDAP bind | SAML 2.0 | OIDC |
|---|---|---|---|
| What the app receives | Success or failure of a password check on a connection | Signed XML assertion with subject and attributes | Signed JWT ID token, plus access and refresh tokens |
| Does the app see the password? | Yes, always | No | No |
| MFA and conditional access | Not in the bind path; the app must add its own | Enforced at the IdP before the assertion is issued | Enforced at the IdP; acr, amr and auth_time tell the app what happened |
| Transport protection | LDAPS (636) or StartTLS on 389; signing and channel binding on AD | HTTPS plus XML Signature, optional XML Encryption | HTTPS plus JWS, optional JWE; PKCE on the code flow |
| Standing credential held by the app | Bind service account password or client certificate | None for login; SP signing key if requests are signed | Client secret or, better, private key JWT or mTLS |
| Typical client | Legacy web apps, appliances, VPNs, Linux PAM, printers, Wi-Fi via RADIUS | Enterprise browser SaaS and older web apps | New web apps, SPAs, mobile, desktop, APIs |
| Main threat | Password exposure, broad bind account, unsigned or cleartext binds | Signature wrapping, missing audience or destination checks, signing key theft | Skipped token validation, implicit flow, redirect URI and mix-up attacks, token theft |
| Session revocation | Disable account in directory; app session lives on | Single Logout, unreliable in practice | Back-Channel Logout and short token lifetimes |
Threat model: LDAP bind authentication
RFC 4513 defines three forms of simple bind: anonymous (empty name and password), unauthenticated (a name with an empty password) and name/password. Each creates a distinct risk when an application uses LDAP for login.
- Cleartext credentials: RFC 4513 says name/password bind is not suitable without confidentiality protection and requires servers that support it to offer a policy that demands TLS, returning
confidentialityRequiredotherwise. A simple bind on port 389 without StartTLS puts the user's directory password on the wire, exposed to adversary-in-the-middle capture (ATT&CK T1557). - StartTLS stripping: RFC 4513 section 6.2 warns that StartTLS adds no security by itself, because an attacker can strip the extension or downgrade the result. Clients must refuse to proceed when security is inadequate, which many application LDAP libraries do not do unless configured.
- The empty password trap: an unauthenticated bind succeeds with a valid DN and an empty password but authenticates nothing. RFC 4513 says servers SHOULD reject it by default with
unwillingToPerformand that clients making authorisation decisions on a successful bind should check the password was not empty. Applications that skip this check let anyone in who knows a username. - Bind service account exposure: most applications first bind as a service account to search for the user's DN, then bind as the user. That service account password sits in a config file, and its read rights often cover the whole directory, so stealing it gives an attacker a tool for reconnaissance (see LDAP Reconnaissance Detection) and for password spraying through the app (T1110).
- Password collection at the app: every user credential passes through the application, its logs and its memory. A compromised app tier is a harvest of valid accounts (T1078).
- No MFA: the bind carries a password, so phishing-resistant authenticators cannot be used. Vendors bolt on OTP fields, but those are weaker than authentication at the IdP.
Threat model: SAML and OIDC
Federation removes the password from the application but moves the risk to token validation and to the signing keys. These are covered in depth in the SAML Security Guide and OAuth 2.0 and OpenID Connect Guide; the short list for this decision:
- SAML signature wrapping and unsigned content: the OWASP SAML Security Cheat Sheet recommends schema validation with local schemas, absolute XPath, signing each assertion or the whole response, confirming the signature reference covers the assertion actually used, and rejecting SHA-1.
- SAML audience and destination: the SP must check Audience against its entity ID,
Destinationagainst its ACS URL andInResponseToagainst the original request ID, or an assertion for one app can be replayed at another. - Unsolicited responses: IdP-initiated SSO has no request to match, so OWASP advises enabling it only when required and allowlisting
RelayState. The trade-offs are in IdP-Initiated vs SP-Initiated SSO. - OIDC token misuse: OIDC Core section 3.1.3.7 requires the client to match
issexactly, confirm itsclient_idinaud, checkexpand matchnonce. Skipping any of these lets tokens issued for another client or another time be accepted (T1550.001 for stolen tokens). - Weak OAuth flows: RFC 9700 (BCP 240, January 2025) says the implicit grant should not be used, the resource owner password credentials grant must not be used, redirect URIs must be matched exactly, and PKCE with S256 is required for public clients.
- Signing key theft: whoever holds the IdP's signing key can mint assertions for anyone. In the SolarWinds SUNBURST and Golden SAML compromise, attackers stole a SAML token-signing certificate and forged tokens that bypassed password and MFA checks (T1606.002). See the Golden SAML Defence Guide.
The net effect: federation concentrates risk in a small number of well-protected keys and validators, whereas LDAP spreads password handling across every application. That concentration is easier to defend.
Hardening an LDAP bind that has to stay
Some systems will authenticate over LDAP for years: network appliances, older Java and PHP apps, Linux hosts through PAM and SSSD, and some vendor products with no federation option. For these, harden in this order.
- Encrypt every bind. Use LDAPS on 636 or StartTLS before the bind, and set the client to verify the server certificate against its subjectAltName as RFC 4513 section 3.1.3 requires. Disable "trust all certificates" options in application settings.
- Require signing on Active Directory. Set Domain controller: LDAP server signing requirements to Require signing in the Default Domain Controller Policy, and Network security: LDAP client signing requirements to Require signing for clients. For AD LDS the registry value is
LDAPServerIntegrity(2 = enabled). - Enforce channel binding for LDAPS. The policy Domain controller: LDAP server channel binding token requirements maps to
LdapEnforceChannelBindingunderHKLM\SYSTEM\CurrentControlSet\Services\NTDS\Parameters: 0 Never, 1 When Supported, 2 Always. Move to 1 first, then 2 once audit events are clean. - Reject unauthenticated and anonymous binds for application use, and confirm the application checks for empty passwords.
- Scope the bind service account. Restrict it to read the OU and attributes the app needs (user DN,
mail,memberOf), deny interactive logon, and store its password in a vault with rotation. Where the platform supports it, replace the password with SASL EXTERNAL and a TLS client certificate. See the Service Account Security Guide. - Restrict the network path. Only the app servers should reach the directory on 389 and 636, and through a dedicated set of domain controllers where possible.
- Add compensating controls. Lockout and throttling at the app, and IP restriction to the app login page, since MFA cannot sit in the bind.
The detailed mechanics of bind types, signing and channel binding are in the LDAP Security Deep Dive Guide.
Fronting a legacy app with federation
When the goal is to remove passwords from the application, there are four patterns, in order of preference.
| Pattern | How it works | When it fits | Residual risk |
|---|---|---|---|
| Native federation | Enable the app's own SAML or OIDC support; keep LDAP only for group lookup by a scoped account, or replace with SCIM | App has a SAML or OIDC option, even in a newer version | Token validation quality in the app's library |
| Identity-aware reverse proxy | A proxy authenticates the user by OIDC or SAML, then passes identity to the app in headers or via Kerberos constrained delegation | Web app with no federation support that accepts header or Kerberos login | App must accept identity only from the proxy; direct access must be blocked |
| Kerberos integrated auth | Windows app uses Kerberos inside the domain; IdP handles remote access | On-premises Windows and IIS apps | Delegation misconfiguration; see the Kerberos Delegation Security Guide |
| Hardened LDAP bind | Keep the bind with all controls above | Appliances and products with no alternative | Password exposure and no MFA remain |
With the reverse proxy pattern, the most common failure is leaving the application reachable directly, so an attacker sends the trusted identity header themselves. Bind the app to the proxy's network or require mutual TLS between them.
Separating authentication from provisioning helps: once login moves to federation, the app often still needs user and group data. SCIM pushes that data without a standing read account; see LDAP vs SCIM.
Decision criteria by application type
| Application | Preferred | Acceptable fallback | Avoid |
|---|---|---|---|
| New in-house web app | OIDC, Authorization Code with PKCE | SAML if the platform standard is SAML | LDAP bind |
| Single-page or mobile app | OIDC with PKCE, backend-for-frontend for SPAs | None | Implicit flow, password grant, LDAP |
| Enterprise SaaS | Whatever federation the vendor supports, usually SAML or OIDC | None | Directory sync of passwords for the SaaS to bind against |
| On-premises Windows web app | Kerberos inside the domain, federation through a proxy for remote users | OIDC if the app supports it | LDAP simple bind |
| Legacy Java or PHP web app | Identity-aware proxy or app upgrade to SAML or OIDC | LDAPS bind with scoped account | Cleartext bind on 389 |
| Network appliance, VPN, Linux host | Vendor SAML or OIDC where offered; certificate auth for devices | LDAPS or RADIUS with MFA at the RADIUS server | Shared domain admin bind account |
| API called by another service | OAuth 2.0 client credentials or workload identity federation | mTLS | LDAP bind with a service account per call |
Small organisations with a cloud identity provider should aim to have no application authenticating against LDAP, and treat each remaining one as an exception with an owner. Large organisations usually have hundreds; inventory them from domain controller events, rank by data sensitivity and user count, and migrate in waves.
Where the choice is between SAML and OIDC, use the decision table in the SAML vs OIDC Guide; for moving existing SAML apps, see SAML to OIDC Migration. Federation assurance can be framed with NIST SP 800-63C: FAL2 requires RP-initiated transactions, strong injection protection and a single RP per assertion, and FAL3 adds a holder-of-key assertion or bound authenticator.
Worked scenario: a regional insurer
A 2,000-person insurer runs Active Directory and a cloud identity provider. Domain controller event 2889 shows 41 client IPs making simple binds, and event 2887 reports unsigned binds every day.
- Inventory: the team maps the 41 IPs to 19 applications: a claims system (Java, LDAP), an intranet wiki, two VPN concentrators, a printer fleet, Jenkins, and assorted Linux hosts.
- Triage: the wiki, Jenkins and the claims system support SAML or OIDC in their current versions. The VPN supports SAML. The printers and one vendor appliance support only LDAP.
- Federate: wiki and Jenkins move to OIDC with PKCE, the claims system to SAML with SP-initiated flow only and signed assertions, and the VPN to SAML, bringing all four under conditional access and phishing-resistant MFA.
- Harden the rest: printers and the appliance move to LDAPS with dedicated bind accounts restricted to one OU, passwords vaulted with 90-day rotation, and network access to two domain controllers only.
- Enforce: after four weeks with event 2889 showing only expected clients, the team sets LDAP server signing to Require signing and channel binding to When Supported, then to Always after events 3039 stop.
- Result: user passwords now pass through two systems instead of 19, and the old shared bind account with domain-wide read is disabled.
Implementation approach
- Turn on diagnostics. Set 16 LDAP Interface Events to 2 on domain controllers to get event 2889 per insecure bind, and collect events 2887, 3039, 3040, 3074 and 3075.
- Build the inventory. Map client IPs and bind identities to applications and owners; record whether each supports SAML, OIDC, Kerberos or only LDAP.
- Pilot one federation migration on a low-risk app, test login, group mapping and logout, and keep the LDAP config disabled but restorable for rollback.
- Migrate in waves by sensitivity. For each app, disable the LDAP login path after cutover rather than leaving both.
- Harden remaining binds with LDAPS, scoped and vaulted bind accounts and network restriction.
- Enforce signing and channel binding in audit, then When Supported, then Always. Rollback is a policy change back to the previous level; keep a change window and a list of clients that failed.
- Review quarterly for new LDAP clients appearing in events.
Detection and measurement
- Event 2889: each unsigned or cleartext bind with client IP and identity; any new IP is a new application to triage.
- Events 3039 and 3074 or 3075: LDAPS binds failing or lacking channel binding.
- Bind account behaviour: searches outside the expected OU, binds from unexpected hosts, or interactive logons by the account. See the Service Account Behavioural Baselining Guide.
- Federation validation failures: SP and RP logs for signature, audience and nonce failures, which may indicate tampering or misconfiguration.
| Metric | Target |
|---|---|
| Applications authenticating users by LDAP bind | Falling each quarter; each remaining one has an owner and exception |
| Daily unsigned or cleartext binds (events 2887 and 2889) | Zero |
| Bind service accounts with directory-wide read | Zero |
| Bind account passwords vaulted and rotated | 100% |
| Federated apps allowing IdP-initiated SSO without business need | Zero |
| OIDC public clients without PKCE | Zero |
Common failure patterns
- The domain-wide bind account: one service account used by every LDAP app, with read on the whole forest and a password unchanged for years.
- Federation added, LDAP left on: the app gets SAML but the LDAP login form still works, so attackers spray passwords through it and bypass MFA.
- Certificate validation disabled: the app uses LDAPS but trusts any certificate, so the encryption protects nothing against interception.
- Empty password accepted: the app treats an unauthenticated bind as success.
- Unsigned or partially signed assertions accepted by a custom SAML integration, or OIDC ID tokens decoded without signature and audience checks.
- Signing key on an ordinary server: the IdP token-signing key is exportable from a server that is not treated as tier zero.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| NIST CSF 2.0 | PR.AA-01, PR.AA-03, PR.DS-02 | Managed credentials, authentication of users and services, data in transit |
| NIST SP 800-53 Rev 5 | IA-2, IA-5, IA-8, SC-8, SC-23, AC-6, AU-2 | Authentication, authenticator management, transmission protection, session authenticity, least privilege for bind accounts, logging |
| NIST SP 800-63C | FAL1, FAL2, FAL3 | Federation assurance for SAML and OIDC |
| CIS Controls v8.1 | 6.7, 12.5, 3.10 | Centralise access control, centralise network AAA, encrypt data in transit |
| ISO/IEC 27001:2022 Annex A | A.5.17, A.8.5, A.8.2 | Authentication information, secure authentication, privileged access rights |
| MITRE ATT&CK v20 | T1557, T1110, T1078, T1606.002, T1550.001 | Bind interception, spraying through apps, valid accounts, forged SAML, stolen tokens |
Practitioner checklist
- Enable LDAP interface diagnostics and list every client making simple or unsigned binds.
- Record for each LDAP-authenticating app whether it supports SAML, OIDC or Kerberos.
- Migrate supported apps to federation and disable their LDAP login path.
- Require LDAPS or StartTLS with certificate validation for every remaining bind.
- Set LDAP server signing to Require signing and channel binding to Always after audit.
- Scope each bind account to the OUs and attributes its app needs, vault and rotate its password.
- Disable IdP-initiated SAML where not needed and enforce PKCE for OIDC public clients.
- Treat IdP signing keys as tier-zero assets and monitor their use.
Standards and references
- IETF: RFC 4511 Lightweight Directory Access Protocol (LDAP): The Protocol
- IETF: RFC 4513 LDAP Authentication Methods and Security Mechanisms
- OpenID Foundation: OpenID Connect Core 1.0
- IETF: RFC 9700 Best Current Practice for OAuth 2.0 Security
- NIST: SP 800-63C Federation and Assertions
- OWASP: SAML Security Cheat Sheet
- Microsoft: LDAP channel binding and LDAP signing requirements (KB4520412)
- Microsoft Learn: How to enable LDAP signing in Windows Server
Related NHI Mgmt Group resources: SAML vs OIDC Guide · Directory Service vs Identity Provider · LDAP Security Deep Dive Guide · SAML to OIDC Migration · PKCE Implementation