ZendHQ Daemon LDAP Authentication and Authorization

LDAP is a lightweight directory access protocol that you can use to authenticate and authorize users in ZendHQ using a central LDAP server like Microsoft Active Directory or OpenLDAP's slapd server. LDAP authentication and authorization complements ZendHQ local Role-Based Access Control (RBAC).

  • There is no requirement to add users to the ZendHQ local RBAC database.

  • Users are authenticated by the remote LDAP server using user name and password.

  • Users are authorized by looking up their group membership on the remote LDAP server:

    • Define a file that maps LDAP group names to local ZendHQ RBAC group names.

    • Add local RBAC groups to the ZendHQ local RBAC database and give the groups access to ZendHQ services.

Important LDAP authentication and authorization is disabled by default. Configure and enable it manually before enabling the Extension.

This article covers the following concepts:

LDAP Authentication and Authorization concepts

Organizations are free to set up their LDAP servers in many different ways, therefore it is not possible to provide a generic ZendHQ LDAP authentication and authorization configuration that would work with all of them. In this document we explain the concept and provide several configuration examples.

In the following example scenario, we use OpenLDAP client programs to demonstrate the steps that the ZendHQ daemon would perform. The hypothetical LDAP server has the following properties:

Property

Description

ldap.example.com hostname of the LDAP server
cn=admin,dc=example.com service user DN (Distinguished Name)
1234 service user password
cn=Users,dc=example.com users and groups LDAP tree
john@example.com user name

Service user is a technical user with LDAP search permissions provided by the LDAP server administrator.

The sample user's LDAP record looks like the following:

dn: john,CN=Users,DC=example.com
objectClass: person
objectClass: user
distinguishedName: CN=john,CN=Users,DC=example.com
memberOf: CN=Developers,CN=Users,DC=example.com
memberOf: CN=Administrators,CN=Builtin,DC=example.com
userPrincipalName: john@example.com

When users request to log in, they provide a user name and password. ZendHQ uses the provided user name, provided service user name and password, and performs a search on the remote LDAP server with a configurable search base and filter:

> ldapsearch -H ldap://ldap.example.com \
             -D 'cn=admin,dc=example.com' -w 1234 \
             -b 'cn=Users,dc=example.com' \
             '(&(userPrincipalName=john@example.com)(objectClass=person)(objectClass=user))' \
             dn

The search must return one single user entry with the user's distinguished name (DN) for it to be a valid user name:

dn: CN=john,CN=Users,DC=example.com

ZendHQ uses the returned user's DN and the password provided by the user to authenticate the user:

> ldapwhoami -H ldap://ldap.example.com \
             -D 'CN=john,CN=Users,DC=example.com' -w '<password>'

When authentication succeeds, ZendHQ performs a search for group names using the provided service user and the user's distinguished name (DN) from the user lookup:

> ldapsearch -H ldap://ldap.example.com \
             -D 'cn=admin,dc=example.com' -w 1234 \
	      -b 'CN=john,CN=Users,DC=example.com' \ 
             '(objectClass=*)' \
              memberOf

The search returns zero, one or multiple memberOf attribute values with distinguished names of groups the user is member of:

memberOf: CN=Developers,CN=Users,DC=example.com
memberOf: CN=Administrators,CN=Builtin,DC=example.com

ZendHQ uses a map file with regular expressions to match LDAP group names to ZendHQ local RBAC group names:

CN=Developers,.*        devel

The LDAP group CN=Developers,CN=Users,DC=example.com matches the regular expression in the map file and the user is assigned to the ZendHQ local RBAC group devel.

ZendHQ LDAP configuration

You find ZendHQ LDAP configuration directives in the zendhqd.ini file located in the $PREFIX/etc/ directory, where $PREFIX is the directory where ZendHQ is installed.

The zendhqd prefix is omitted in the following table; the full directive name is always zendhqd.$DIRECTIVE:

Directive

Usage

ldap.valid_user_regex Defines the regular expression for validating user names
ldap.local_rbac_fallback Enables local RBAC fall-back
ldap.server_url Defines the LDAP server url
ldap.lookup_user_dn Enables user lookup
ldap.service_user_dn Defines the service user DN
ldap.service_user_psw Defines the service user password
ldap.user_auth_dn Defines the User DN template for authentication
ldap.group_lookup_base Defines the search base for looking up group names
ldap.group_lookup_filter Defines the search filter for looking up group names
ldap.group_lookup_attribute Defines the group name attribute
ldap.user_lookup_base Defines the search base for looking up user names
ldap.user_lookup_filter Defines the search filter for looking up user names
ldap.groups_map Defines the name of the groups map file

How to enable ZendHQ LDAP Authentication and Authorization

LDAP authentication and authorization is implemented as a separate ZendHQ extension, which is disabled by default. You must configure LDAP authentication and authorization first before enabling the extension. Failures in configuration automatically disable the LDAP authentication and authorization.

To enable the LDAP authentication and authorization

  1. Set all the required configuration directives in the zendhqd.ini file.

  2. Uncomment the following line in the ZendHQ configuration file:

    zendhqd.extension = zendhq_ldap
  3. Restart the ZendHQ daemon now.

The extension and its configuration directives are loaded and enabled.

Templates

Use templates to build LDAP query parameters, like the base DN, filter, etc.

Templates can contain variable names in the form {<name>}, which are expanded to actual values. For example, if the login user name is admin, a template string "CN={user},DC=example.com" is expanded to "CN=admin,DC=example.com".

The following variables are supported:

Variable Description
{user} Login user name
{user_dn} Distinguished name (DN) of the user from the LDAP lookup

Directives

The following ZendHQ configuration directives are supported:

  • ldap.valid_user_regex

    Defines the regular expression for validating user names. All user names are checked against this regular expression before sending them to the LDAP server. Works as a filter for valid user names and protects against potential LDAP injection attacks.

    The default value is undefined.

    Example:

    zendhqd.ldap.valid_user_regex = "[a-z][.a-z0-9_-]*"

  • ldap.local_rbac_fallback

    Defines whether to use local RBAC fall-back if remote LDAP authentication fails. Set it to true or false. With the local RBAC fall-back enabled, users can still log in using the local RBAC database even if the remote LDAP authentication fails. The users must be defined in the local RBAC database.

    The default value is false.

    Example:

zendhqd.ldap.local_rbac_fallback = false
  • ldap.server_url

    Defines a comma- or whitespace-separated list of LDAP server URIs containing only the schema, the host, and the port fields. Apart from ldap, other recognized values of the schema field are ldaps (LDAP over TLS) and ldapi (LDAP over IPC). The first server in the list that responds is used for authentication and authorization.

    No default value.

    Example:

zendhqd.ldap.server_url = ldap://ldap.example.com
  • ldap.lookup_user_dn

    Defines whether to look up users or not.

    • Set this to false to authenticate users directly without LDAP lookup.

    • Set this to true if two-step authentication is required and the user must be looked up first in the LDAP server. If you set this directive to true, then you must also set ldap.service_user_dn, ldap.service_user.psw, ldap.user_lookup_base, ldap.user_lookup_filter, and ldap.user_lookup_attribute directives.

    The default value is false

    Example:

zendhqd.ldap.lookup_user_dn = false
  • ldap.service_user_dn

    Defines the service user Distinguished Name (DN). The service user is used to look up users and groups on the LDAP server. Use an empty value for anonymous access or leave undefined to use the user being authenticated.
    If theldap.lookup_user_dn directive is set to true, setting the service user (possibly to an empty string for anonymous access) is required.

    Default value is undefined.

    Example:

zendhqd.ldap.service_user_dn  = "CN=admin,CN=Users,DC=ldap,DC=example.com"
  • ldap.service_user_psw

    Defines the service user password.

    The default value is undefined.

    Example:

zendhqd.ldap.service_user_psw = "1234"
  • ldap.user_auth_dn

    Defines the user DN template used for authentication.

    This value is passed to the LDAP server as the Distinguished Name along with the user password when binding to the LDAP directory during the authentication.

    Defaults to "{user}" when the ldap.lookup_user_dn directive is false. Defaults to "{user_dn}" when the ldap.lookup_user_dn directive is true.

    Example:

zendhqd.ldap.user_auth_dn = "{user}"
  • ldap.group_lookup_base

    Defines the LDAP search base template for looking up group names. Used as a search base when looking up group names.

    Default value is undefined.

    Example:

zendhqd.ldap.group_lookup_base = "{user_dn}"
  • ldap.group_lookup_filter

    Defines the LDAP search filter template for looking up group names. Used as a search filter for the specific user when looking up group names.

    Default value is undefined.

    Example:

zendhqd.ldap.group_lookup_filter = "(objectClass=*)"
  • ldap.group_lookup_attribute

    Defines the name of the LDAP attribute containing group names. Values of this attribute are used as group names for the given user. In addition to existing LDAP attributes, dn can be used for the Distinguished Name.

    Default value is undefined.

    Example:

zendhqd.ldap.group_lookup_attribute = "memberOf"
  • ldap.user_lookup_base

    Defines the LDAP search base template for looking up users. Used as a search base when looking up users. If the the ldap.lookup_user_dn directive is set to true, this directive is required.

    Default value is undefined.

    Example:

zendhqd.ldap.user_lookup_base = "CN=Users,DC=ldap,DC=example.com"
  • ldap.user_lookup_filter

    Defines the LDAP search filter template for looking up users. Used as a search filter for the specific user when looking users. If the ldap.lookup_user_dn directive is set to true, this directive is required.

    Default value is undefined.

    Example:

endhqd.ldap.user_lookup_filter = "(&(userPrincipalName={user})
		(objectClass=person)
		(objectClass=user))"
  • ldap.groups_map

    Defines the name of the file that maps LDAP group names to ZendHQ RBAC group names. Each line in the file must contain a regular expression matching LDAP group names followed by a ZendHQ RBAC group name separated by at least two spaces or <TAB> characters.

    Default value is $PREFIX/etc/ldap_groups.

    Example:

zendhqd.ldap.groups_map = /opt/zend/zendphp/etc/ldap_groups

LDAP groups file

The LDAP groups file maps LDAP group names to ZendHQ local RBAC group names. The map file is a regular text file and must be stored in the location configured with the ldap.groups_map directive.

  • Each line in this file must contain a regular expression matching LDAP group names followed by a ZendHQ RBAC group name separated by at least two spaces or <TAB> characters.

  • Lines starting with ; or # characters are comments and ignored when reading the file.

  • The file can contain multiple lines that are processed in the order they appear in this file. The first regular expression matching the LDAP group name will be used.

Example:

CN=Developers,.*       devel

In this example, the ZendHQ RBAC group name devel is used for the LDAP group name "CN=Developers,CN=Users,DC=ldap,DC=example.com".

Examples

The following are ZendHQ LDAP configuration examples for some LDAP servers.

Active Directory without user lookup

A Microsoft Active Directory configured to allow user authentication using the userPrincipalName attribute value.

  • All the users have LDAP search permissions and LDAP service user is not required.

  • Users are expected to log in with their name only without the @domain part and we use the {user}@example.com.org template to build the userPrincipalName attribute value.

  • User LDAP records contain the memberOf attribute with LDAP group names.

Given a user LDAP record for the user john:

dn: CN=john,CN=Users,DC=example.com,DC=org
objectClass: person
objectClass: user
distinguishedName: CN=john,CN=Users,DC=example.com,DC=org
memberOf: CN=Developers,CN=Users,DC=example.com,DC=org
memberOf: CN=Administrators,CN=Builtin,DC=example.com,DC=org
userPrincipalName: john@example.com.org

Use the following ZendHQ LDAP configuration directives:

zendhqd.ldap.lookup_user_dn = false
;zendhqd.ldap.service_user_dn  =
;zendhqd.ldap.service_user_psw =
zendhqd.ldap.user_auth_dn = "{user}@example.com.org"
zendhqd.ldap.group_lookup_base = "CN=Users,DC=example.com,DC=org"
zendhqd.ldap.group_lookup_filter = \
   "(&(userPrincipalName={user}@example.com.org)(objectClass=person)(objectClass=user))"
		zendhqd.ldap.group_lookup_attribute = "memberOf"

Active Directory with user lookup

A Microsoft Active Directory configured to require user distinguished name for authentication and a service user to lookup users and groups.

  • Users are expected to log in with their full login name user@domain matching the userPrincipalName LDAP attribute.

  • User LDAP records contain the memberOf attribute with LDAP group names.

Given a user LDAP record for the user john@example.com.org:

dn: CN=john,CN=Users,DC=example.com,DC=org
objectClass: person
objectClass: user
distinguishedName: CN=john,CN=Users,DC=example.com,DC=org
memberOf: CN=Developers,CN=Users,DC=example.com,DC=org
memberOf: CN=Administrators,CN=Builtin,DC=example.com,DC=org
userPrincipalName: john@example.com.org

Use the following ZendHQ LDAP configuration directives:

zendhqd.ldap.lookup_user_dn = true
zendhqd.ldap.service_user_dn  = cn=admin,dc=example.com,dc=org
zendhqd.ldap.service_user_psw = 1234
zendhqd.ldap.user_lookup_base = "CN=Users,DC=example.com,DC=org"
zendhqd.ldap.user_lookup_filter = \
    "(&(userPrincipalName={user})(objectClass=person)(objectClass=user))"
zendhqd.ldap.user_auth_dn = "{user_dn}"
zendhqd.ldap.group_lookup_base = "{user_dn}"
			zendhqd.ldap.group_lookup_filter = "(objectClass=*)"
			

zendhqd.ldap.group_lookup_attribute = "memberOf"

OpenLDAP server with user and group lookup

An OpenLDAP server configured with separate user and group records and requiring a service user for lookup.

  • Users are expected to log in with their user name matching the uid LDAP attribute.

  • Group LDAP records contain member attributes with user distinguished names belonging to that group.

Given a user LDAP record for the user john:

dn: uid:john,ou=users,dc=example.com,dc=org
    objectClass: person
    objectClass: inetOrgPerson
uid: john

And a group LDAP record for the group developers:

dn: cn=developers,ou=groups,dc=example.com,dc=org
    objectClass: groupOfNames
member: uid=admin,ou=users,dc=example.com,dc=org
member: uid=john,ou=users,dc=example.com,dc=org

Use the following ZendHQ LDAP configuration directives:

zendhqd.ldap.lookup_user_dn = true
zendhqd.ldap.service_user_dn  = cn=admin,dc=example.com,dc=org
zendhqd.ldap.service_user_psw = 1234
zendhqd.ldap.user_lookup_base = "ou=users,dc=example.com,dc=org"
zendhqd.ldap.user_lookup_filter = \
    "(&(uid={user})(objectClass=person)(objectClass=inetOrgPerson))"
zendhqd.ldap.user_auth_dn = "{user_dn}"
zendhqd.ldap.group_lookup_base = "ou=groups,dc=example.com,dc=org"
zendhqd.ldap.group_lookup_filter = \
    "(&(member={user_dn})(objectClass=groupOfNames))"
zendhqd.ldap.group_lookup_attribute = "dn"