%docentities; ]> &adminguide;
Overview The LDAP module implements an LDAP search interface for &kamailio;. It exports script functions to perform an LDAP search operation and to store the search results as &kamailio; AVPs. This allows for using LDAP directory data in the &kamailio; SIP message routing script. The following features are offered by the LDAP module: LDAP search function based on a LDAP URL LDAP result parsing functions to store LDAP data as AVP variables Support for accessing multiple LDAP servers LDAP SIMPLE authentication LDAP server failover and automatic reconnect Configurable LDAP connection and bind timeouts Module API for LDAP search operations that can be used by other &kamailio; modules The module implementation makes use of the open source OpenLDAP library available on most UNIX/Linux platforms. Besides LDAP server failover and automatic reconnect, this module can handle multiple LDAP sessions concurrently allowing access to data stored on different LDAP servers. Each &kamailio; worker process maintains one LDAP TCP connection per configured LDAP server. This enables parallel execution of LDAP requests and offloads LDAP concurrency control to the LDAP server(s). An LDAP search module API is provided that can be used by other &kamailio; modules. A module using this API does not have to implement LDAP connection management and configuration, while still having access to the full OpenLDAP API for searching and result handling. Since LDAP server implementations are optimized for fast read access they are a good choice to store SIP provisioning data. Performance tests have shown that this module achieves lower data access times and higher call rates than other database modules like e.g. the &kamailio; MYSQL module.
Usage Basics LDAP sessions is specified in an external configuration file (as described in ). Each of these LDAP sessions includes LDAP server access parameters like server hostname or connection timeouts. Normally only a single LDAP session per process will be used unless there is a need to access more than one LDAP server. The LDAP session name will then be used in the &kamailio; configuration script to refer to a specific LDAP session. The ldap_search function () performs an LDAP search operation. It expects an LDAP URL as input which includes the LDAP session name and search parameters. The section provides a quick overview on LDAP URLs. The result of a LDAP search is stored internally and can be accessed with one of the ldap_result* functions. ldap_result () stores resulting LDAP attribute values as AVPs. ldap_result_check () is a convenience function to compare a string with LDAP attribute values using regular expression matching. Finally, ldap_result_next () allows using LDAP search queries that return more than one LDAP entry. All ldap_result* functions always access the LDAP result set from the last ldap_search call. This should be kept in mind when calling ldap_search more than once in the &kamailio; configuration script.
LDAP URLs ldap_search expects an LDAP URL as argument. This section describes the format and semantics of an LDAP URL. RFC 4516 describes the format of an LDAP Uniform Resource Locator (URL). An LDAP URL represents an LDAP search operation in a compact format. The LDAP URL format is defined as follows (slightly modified, refer to section 2 of for ABNF notation):
ldap://[ldap_session_name][/dn?attrs[?scope[?filter]]]]
ldap_session_name An LDAP session name as defined in the LDAP configuration file. (RFC 4516 defines this as LDAP hostport parameter) dn Base Distinguished Name (DN) of LDAP search or target of non-search operation, as defined in RFC 4514 attrs Comma separated list of LDAP attributes to be returned scope Scope for LDAP search, valid values are base, one, or sub filter LDAP search filter definition following rules of RFC 4515 The following table lists characters that have to be escaped in LDAP search filters: RFC 4515 Escaping Rules * \2a ( \28 ) \29 \ \5c
Non-URL characters in an LDAP URL have to be escaped using percent-encoding (refer to section 2.1 of RFC 4516). In particular this means that any "?" character in an LDAP URL component must be written as "%3F", since "?" is used as a URL delimiter. The exported function ldap_filter_url_encode () implements RFC 4515/4516 LDAP search filter and URL escaping rules.
Dependencies
&kamailio; Modules The module depends on the following modules (the listed modules must be loaded before this module): No dependencies on other &kamailio; modules.
External Libraries or Applications The following libraries or applications must be installed before running &kamailio; with this module loaded: OpenLDAP library (libldap) v2.1 or greater, libldap header files (libldap-dev) are needed for compilation OpenSSL library if you compile your OpenLDAP library with SSL/TLS support.
LDAP Configuration File The module reads an external configuration file at module initialization time that includes LDAP session definitions.
Configuration File Syntax The configuration file follows the Windows INI file syntax, section names are enclosed in square brackets:[Section_Name]Any section can contain zero or more configuration key assignments of the form key = value ; comment Values can be given enclosed with quotes. If no quotes are present, the value is understood as containing all characters between the first and the last non-blank characters. Lines starting with a hash sign and blank lines are treated as comments. Each section describes one LDAP session that can be referred to in the &kamailio; configuration script. Using the section name as the host part of an LDAP URL tells the module to use the LDAP session specified in the respective section. An example LDAP session specification looks like: [example_ldap] ldap_server_url = "ldap://ldap1.example.com, ldap://ldap2.example.com" ldap_bind_dn = "cn=sip_proxy,ou=accounts,dc=example,dc=com" ldap_bind_password = "pwd" ldap_network_timeout = 500 ldap_client_bind_timeout = 500 The configuration keys are explained in the following section. This LDAP session can be referred to in the routing script by using an LDAP URL like e.g.ldap://example_ldap/cn=admin,dc=example,dc=com
LDAP Session Settings ldap_server_url (mandatory) LDAP URL including fully qualified domain name or IP address of LDAP server optionally followed by a colon and TCP port to connect: ldap://<FQDN/IP>[:<port>]. Failover LDAP servers can be added, each separated by a comma. In the event of connection errors, the module tries to connect to servers in order of appearance. To connect over TLS/SSL, use ldaps://. Default value: none, this is a mandatory setting <varname>ldap_server_url</varname> examples ldap_server_url = "ldap://localhost" ldap_server_url = "ldaps://ldap.example.com:7777" ldap_server_url = "ldap://ldap1.example.com, ldap://ldap2.example.com:80389" ldap_version (optional) Supported LDAP versions are 2 and 3. Default value: 3 (LDAPv3) <varname>ldap_version</varname> example ldap_version = 2 ldap_bind_dn (optional) Authentication user DN used to bind to LDAP server (module currently only supports SIMPLE_AUTH). Empty string enables anonymous LDAP bind. Default value: (empty string --> anonymous bind) <varname>ldap_bind_dn</varname> example ldap_bind_dn = "cn=root,dc=example,dc=com"; ldap_bind_password (optional) Authentication password used to bind to LDAP server (SIMPLE_AUTH). Empty string enables anonymous bind. Default value: (empty string --> anonymous bind) <varname>ldap_bind_password</varname> example ldap_bind_password = "secret"; ldap_network_timeout (optional) LDAP TCP connect timeout in milliseconds. Setting this parameter to a low value enables fast failover if ldap_server_url contains more than one LDAP server addresses. Default value: 1000 (one second) <varname>ldap_network_timeout</varname> example ldap_network_timeout = 500 ; setting TCP timeout to 500 ms ldap_client_bind_timeout (optional) LDAP bind operation timeout in milliseconds. Default value: 1000 (one second) <varname>ldap_client_bind_timeout</varname> example ldap_client_bind_timeout = 1000
Configuration File Example The following configuration file example includes two LDAP session definitions that could be used e.g. for accessing H.350 data and do phone number to name mappings. Example LDAP Configuration File # LDAP session "sipaccounts": # # - using LDAPv3 (default) # - two redundant LDAP servers # [sipaccounts] ldap_server_url = "ldap://h350-1.example.com, ldap://h350-2.example.com" ldap_bind_dn = "cn=sip_proxy,ou=accounts,dc=example,dc=com" ldap_bind_password = "pwd" ldap_network_timeout = 500 ldap_client_bind_timeout = 500 # LDAP session "campus": # # - using LDAPv2 # - anonymous bind # [campus] ldap_version = 2 ldap_server_url = "ldap://ldap.example.com" ldap_network_timeout = 500 ldap_client_bind_timeout = 500
Parameters
config_file (string) Full path to LDAP configuration file. Default value: /usr/local/etc/&kamailiobinary;/ldap.cfg <varname>config_file</varname> parameter usage modparam("ldap", "config_file", "/usr/local/etc/&kamailiobinary;/ldap.ini")
Functions
ldap_search(ldap_url) Performs an LDAP search operation using given LDAP URL and stores result internally for later retrieval by ldap_result* functions. If one or more LDAP entries are found the function returns the number of found entries which evaluates to TRUE in the &kamailio; configuration script. It returns -1 (FALSE) in case no LDAP entry was found, and -2 (FALSE) if an internal error like e.g. an LDAP error occurred. Function Parameters: ldap_url An LDAP URL defining the LDAP search operation (refer to for a description of the LDAP URL format). The hostport part must be one of the LDAP session names declared in the LDAP configuration script. &kamailio; pseudo variables and AVPs included in ldap_url do get substituted with their value. Example Usage of ldap_url Search with LDAP session named sipaccounts, base ou=sip,dc=example,dc=com, one level deep using search filter (cn=schlatter) and returning all attributes: ldap://sipaccounts/ou=sip,dc=example,dc=com??one?(cn=schlatter) Subtree search with LDAP session named ldap1, base dc=example,dc=com using search filter (cn=$(avp(s:name))) and returning SIPIdentityUserName and SIPIdentityServiceLevel attributes ldap://ldap_1/dc=example,dc=com? SIPIdentityUserName,SIPIdentityServiceLevel?sub?(cn=$(avp(s:name))) Return Values: n > 0 (TRUE): Found n matching LDAP entries -1 (FALSE): No matching LDAP entries found -2 (FALSE): LDAP error (e.g. LDAP server unavailable), or internal error This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, and ONREPLY_ROUTE. Example Usage ... # ldap search if (!ldap_search("ldap://sipaccounts/ou=sip,dc=example,dc=com??one?(cn=$rU)")) { switch ($retcode) { case -1: # no LDAP entry found sl_send_reply("404", "User Not Found"); exit; case -2: # internal error sl_send_reply("500", "Internal server error"); exit; default: exit; } } xlog("L_INFO", "ldap_search: found [$retcode] entries for (cn=$rU)"); # save telephone number in $avp(s:tel_number) ldap_result("telephoneNumber/$avp(s:tel_number)"); ...
ldap_result("ldap_attr_name/avp_spec[/avp_type]" [, regex_subst]) This function converts LDAP attribute values into AVPs for later use in the message routing script. It accesses the LDAP result set fetched by the last ldap_search call. ldap_attr_name specifies the LDAP attribute name who's value will be stored in AVP avp_spec. Multi valued LDAP attributes generate an indexed AVP. The optional regex_subst parameter allows to further define what part of an attribute value should be stored as AVP. An AVP can either be of type string or integer. As default, ldap_result stores LDAP attribute values as AVP of type string. The optional avp_type parameter can be used to explicitly specify the type of the AVP. It can be either str for string, or int for integer. If avp_type is specified as int then ldap_result tries to convert the LDAP attribute values to integer. In this case, the values are only stored as AVP if the conversion to integer is succesfull. Function Parameters: ldap_attr_name The name of the LDAP attribute who's value should be stored, e.g. SIPIdentityServiceLevel or telephonenumber avp_spec Specification of destination AVP, e.g. $avp(s:service_level) or $avp(i:12) avp_type Opional specification of destination AVP type, either str or int. If this parameter is not specified then the LDAP attribute values are stored as AVP of type string. regex_subst Regex substitution that gets applied to LDAP attribute value before storing it as AVP, e.g. "/^sip:(.+)$/\1/" to strip off "sip:" from the beginning of an LDAP attribute value. Return Values: n > 0 (TRUE) LDAP attribute ldap_attr_name found in LDAP result set and n LDAP attribute values stored in avp_spec -1 (FALSE) No LDAP attribute ldap_attr_name found in LDAP result set -2 (FALSE) Internal error occurred This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, and ONREPLY_ROUTE. Example Usage ... # ldap_search call ... # save SIPIdentityServiceLevel in $avp(s:service_level) if (!ldap_result("SIPIdentityServiceLevel/$avp(s:service_level)")) { switch ($retcode) { case -1: # no SIPIdentityServiceLevel found sl_send_reply("403", "Forbidden"); exit; case -2: # internal error sl_send_reply("500", "Internal server error"); exit; default: exit; } } # save SIP URI domain in $avp(i:10) ldap_result("SIPIdentitySIPURI/$avp(i:10)", "/^[^@]+@(.+)$/\1/"); ...
ldap_result_check("ldap_attr_name/string_to_match" [, regex_subst]) This function compares ldap_attr_name's value with string_to_match for equality. It accesses the LDAP result set fetched by the last ldap_search call. The optional regex_subst parameter allows to further define what part of the attribute value should be used for the equality match. If ldap_attr_name is multi valued, each value is checked against string_to_match. If one or more of the values do match the function returns 1 (TRUE). Function Parameters: ldap_attr_name The name of the LDAP attribute who's value should be matched, e.g. SIPIdentitySIPURI string_to_match String to be matched. Included AVPs and pseudo variabels do get expanded. regex_subst Regex substitution that gets applied to LDAP attribute value before comparing it with string_to_match, e.g. "/^[^@]@+(.+)$/\1/" to extract the domain part of a SIP URI Return Values: 1 (TRUE) One or more ldap_attr_name attribute values match string_to_match (after regex_subst is applied) -1 (FALSE) ldap_attr_name attribute not found or attribute value doesn't match string_to_match (after regex_subst is applied) -2 (FALSE) Internal error occurred This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, and ONREPLY_ROUTE. Example Usage ... # ldap_search call ... # check if 'sn' ldap attribute value equals username part of R-URI, # the same could be achieved with ldap_result_check("sn/$rU") if (!ldap_result_check("sn/$ru", "/^sip:([^@]).*$/\1/")) { switch ($retcode) { case -1: # R-URI username doesn't match sn sl_send_reply("401", "Unauthorized"); exit; case -2: # internal error sl_send_reply("500", "Internal server error"); exit; default: exit; } } ...
ldap_result_next() An LDAP search operation can return multiple LDAP entries. This function can be used to cycle through all returned LDAP entries. It returns 1 (TRUE) if there is another LDAP entry present in the LDAP result set and causes ldap_result* functions to work on the next LDAP entry. The function returns -1 (FALSE) if there are no more LDAP entries in the LDAP result set. Return Values: 1 (TRUE) Another LDAP entry is present in the LDAP result set and result pointer is incremented by one -1 (FALSE) No more LDAP entries are available -2 (FALSE) Internal error This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, and ONREPLY_ROUTE. Example Usage ... # ldap_search call ... ldap_result("telephonenumber/$avp(s:tel1)"); if (ldap_result_next()) { ldap_result("telephonenumber/$avp(s:tel2)"); } if (ldap_result_next()) { ldap_result("telephonenumber/$avp(s:tel3)"); } if (ldap_result_next()) { ldap_result("telephonenumber/$avp(s:tel4)"); } ...
ldap_filter_url_encode(string, avp_spec) This function applies the following escaping rules to string and stores the result in AVP avp_spec: ldap_filter_url_encode() escaping rules character in string gets replaced with defined in * \2a RFC 4515 ( \28 RFC 4515 ) \29 RFC 4515 \ \5c RFC 4515 ? %3F RFC 4516
The string stored in AVP avp_spec can be safely used in an LDAP URL filter string. Function Parameters: string String to apply RFC 4515 and URL escpaing rules to. AVPs and pseudo variables do get expanded. Example: "cn=$avp(s:name)" avp_spec Specification of AVP to store resulting RFC 4515 and URL encoded string, e.g. $avp(s:ldap_search) or $avp(i:10) Return Values: 1 (TRUE) RFC 4515 and URL encoded filter_component stored as AVP avp_name -1 (FALSE) Internal error This function can be used from REQUEST_ROUTE, FAILURE_ROUTE, BRANCH_ROUTE, and ONREPLY_ROUTE. Example Usage ... if (!ldap_filter_url_encode("cn=$avp(s:name)", "$avp(s:name_esc)")) { # RFC 4515/URL encoding failed --> silently discard request exit; } xlog("L_INFO", "encoded LDAP filter component: [$avp(s:name_esc)]\n"); if (ldap_search( "ldap://h350/ou=commObjects,dc=example,dc=com??sub?($avp(s:name_esc))")) { ... } ...
Installation & Running
Compiling the LDAP module OpenLDAP library (libldap) and header files (libldap-dev) v2.1 or greater (this module was tested with v2.1.3 and v2.3.32) are required for compiling the LDAP module. The OpenLDAP source is available at http://www.openldap.org/. Note that TLS support needs to be added a compile time for the libraries. The OpenLDAP library is available pre-compiled for most UNIX/Linux flavors. On Debian/Ubuntu, the following packages must be installed: # apt-get install libldap2 libldap2-dev.