Skip to main content

ldap-auth-advanced

The ldap-auth-advanced plugin authenticates clients against an LDAP directory, such as OpenLDAP or Active Directory, and optionally maps the authenticated directory user onto a consumer.

The plugin resolves users with a search-then-bind flow. It first searches base_dn for an entry whose attribute matches the user name supplied by the client, and then binds as the entry it found, using the password supplied by the client. Because the user's distinguished name (DN) is discovered rather than constructed, the directory layout does not have to be encoded in the gateway configuration, and users can live at different depths of the tree.

When consumer_required is enabled, which is the default, the plugin then looks for a consumer whose credential records the DN that was resolved. On a match, the gateway adds headers such as X-Consumer-Username and X-Credential-Identifier to the request before proxying it upstream, so per-consumer plugins, rate limits, and analytics apply to LDAP-authenticated traffic like any other identity. Setting consumer_required to false authenticates against the directory without requiring a consumer.

Available in API7 Enterprise from version 3.10.5.

info

The plugin reads credentials from the Authorization header, or from Proxy-Authorization when that header carries usable credentials. The scheme word is determined by header_type: with the default ldap, clients send Authorization: ldap <base64(username:password)>; with basic, they send an ordinary Authorization: Basic <base64(username:password)> header, which lets existing HTTP Basic clients authenticate unchanged.

Examples

The examples below demonstrate how you can work with the ldap-auth-advanced plugin for different scenarios.

Prerequisites

The examples assume an LDAP directory reachable at 192.168.1.10:389 that holds user entries under ou=users,dc=example,dc=org, with a user whose uid is johndoe and whose password is john-secret. Searches are performed as cn=admin,dc=example,dc=org. Adjust these values for your own directory.

Authenticate Against an LDAP Directory

The following example demonstrates how to authenticate clients against an LDAP directory without mapping them onto consumers, by setting consumer_required to false.

Create a route with ldap-auth-advanced:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "ldap-auth-route",
"uri": "/anything",
"plugins": {
"ldap-auth-advanced": {
"ldap_uri": "192.168.1.10:389",
"base_dn": "ou=users,dc=example,dc=org",
"attribute": "uid",
"bind_dn": "cn=admin,dc=example,dc=org",
"ldap_password": "admin-secret",
"consumer_required": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Verify with Valid Credentials

Send a request to the route with the directory user's credentials, base64 encoded and presented in the ldap scheme:

curl -i "http://127.0.0.1:9080/anything" \
-H "Authorization: ldap $(printf '%s' 'johndoe:john-secret' | base64)"

You should receive an HTTP/1.1 200 OK response.

Verify with Invalid Credentials

Send a request to the route with an incorrect password:

curl -i "http://127.0.0.1:9080/anything" \
-H "Authorization: ldap $(printf '%s' 'johndoe:wrong-password' | base64)"

You should receive an HTTP/1.1 401 Unauthorized response:

WWW-Authenticate: ldap realm="ldap"
{"message":"Authorization required"}

Verify without Credentials

Send a request to the route without any credentials:

curl -i "http://127.0.0.1:9080/anything"

You should receive an HTTP/1.1 401 Unauthorized response.

Map LDAP Users to Consumers

The following example demonstrates how to map a directory user onto a consumer, so that consumer-scoped configurations apply to their traffic. The consumer's credential records the user's full DN, which is the value the plugin resolves through its directory search.

info

Consumer credentials of type ldap-auth-advanced are created through the Admin API or the Dashboard. ADC and the Ingress Controller currently support only key-auth, basic-auth, jwt-auth, and hmac-auth credentials.

Create a consumer johndoe:

curl "http://127.0.0.1:9180/apisix/admin/consumers" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"username": "johndoe"
}'

Create an ldap-auth-advanced credential for the consumer, recording the DN of the directory entry:

curl "http://127.0.0.1:9180/apisix/admin/consumers/johndoe/credentials" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "cred-john-ldap-auth",
"plugins": {
"ldap-auth-advanced": {
"user_dn": "uid=johndoe,ou=users,dc=example,dc=org"
}
}
}'

Create a route with ldap-auth-advanced, leaving consumer_required at its default of true:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "ldap-auth-consumer-route",
"uri": "/anything",
"plugins": {
"ldap-auth-advanced": {
"ldap_uri": "192.168.1.10:389",
"base_dn": "ou=users,dc=example,dc=org",
"attribute": "uid",
"bind_dn": "cn=admin,dc=example,dc=org",
"ldap_password": "admin-secret"
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Send a request to the route with the directory user's credentials:

curl -i "http://127.0.0.1:9080/anything" \
-H "Authorization: ldap $(printf '%s' 'johndoe:john-secret' | base64)"

You should receive an HTTP/1.1 200 OK response, and the upstream should see the consumer headers:

{
"headers": {
"X-Consumer-Username": "johndoe",
"X-Credential-Identifier": "cred-john-ldap-auth",
...
},
...
}

A directory user who authenticates successfully but whose DN is not recorded on any consumer credential receives HTTP/1.1 401 Unauthorized.

Accept the HTTP Basic Authentication Scheme

The following example demonstrates how to accept credentials in the standard HTTP Basic scheme instead of the ldap scheme, so that existing Basic clients work unchanged.

Set header_type to basic on the route:

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "ldap-auth-basic-route",
"uri": "/anything",
"plugins": {
"ldap-auth-advanced": {
"ldap_uri": "192.168.1.10:389",
"base_dn": "ou=users,dc=example,dc=org",
"attribute": "uid",
"bind_dn": "cn=admin,dc=example,dc=org",
"ldap_password": "admin-secret",
"header_type": "basic",
"consumer_required": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Send a request using an ordinary Basic credential:

curl -i "http://127.0.0.1:9080/anything" -u johndoe:john-secret

You should receive an HTTP/1.1 200 OK response. An unauthenticated request is now challenged with the Basic scheme:

WWW-Authenticate: Basic realm="ldap"

Connect to the Directory Over TLS

The following example demonstrates how to reach the directory over LDAPS. Set use_ldaps and point ldap_uri at the LDAPS port; when the port is omitted, 636 is used under LDAPS and 389 otherwise. Use use_starttls instead to upgrade a plaintext connection on port 389. The two options are mutually exclusive.

curl "http://127.0.0.1:9180/apisix/admin/routes" -X PUT \
-H "X-API-KEY: ${ADMIN_API_KEY}" \
-d '{
"id": "ldaps-auth-route",
"uri": "/anything",
"plugins": {
"ldap-auth-advanced": {
"ldap_uri": "192.168.1.10:636",
"use_ldaps": true,
"base_dn": "ou=users,dc=example,dc=org",
"attribute": "uid",
"bind_dn": "cn=admin,dc=example,dc=org",
"ldap_password": "admin-secret",
"consumer_required": false
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"httpbin.org:80": 1
}
}
}'

Certificate verification is controlled by ssl_verify, which is enabled by default. Leave it enabled and make sure the directory's issuing CA is trusted by the gateway.