[[ldap]]
=== Configuring an LDAP Realm

A secure Elasticsearch cluster can authenticate users from a Lightweight Directory Access Protocol (LDAP) directory.
With LDAP Authentication, you can assign roles to LDAP groups.  When a user authenticates with LDAP, the privileges for
that user are the union of all privileges defined by the roles assigned to the set of groups that the user belongs to.

This section discusses configuration for an LDAP Realm.

==== LDAP Overview

LDAP stores users and groups hierarchically, similar to the way folders are grouped in a file system. The path to any
entry is a _Distinguished Name_, or DN. A DN uniquely identifies a user or group. User and group names typically use
attributes such as _common name_ (`cn`) or _unique ID_ (`uid`). An LDAP directory's hierarchy is built from containers 
such as the _organizational unit_ (`ou`), _organization_ (`o`), or _domain controller_ (`dc`).

LDAP ignores white space in a DN definition. The following two DNs are equivalent:

[source,shell]
---------------------------------
"cn=admin,dc=example,dc=com"
"cn =admin ,dc= example , dc = com"
---------------------------------

Although optional, connections to the LDAP server should use the Secure Sockets Layer (SSL/TLS) protocol to protect
passwords. Clients and nodes that connect via SSL/TLS to the LDAP server require the certificate or the root CA for the
server. These certificates should be put into each node's keystore/truststore.

[[ldap-realms]]
==== LDAP Realm Settings
Like all realms, the `ldap` realm is configured under the `shield.authc.realms` settings namespace in the
`elasticsearch.yml` file. The LDAP realm supports two modes of operation, a user search mode and a mode with specific
templates for user DNs.

[[ldap-user-search]]
===== LDAP Realm with User Search added[1.1.0]
A LDAP user search is the most common mode of operation. In this mode, a specific user with permission to search the LDAP
is used to seach for the user DN based on the username and a LDAP attribute. The following snippet shows an example of
such configuration:

.Example LDAP Realm Configuration with User Search
[source, yaml]
------------------------------------------------------------
shield:
  authc:
    realms:
      ldap1:
        type: ldap
        order: 0
        url: "ldaps://ldap.example.com:636"
        bind_dn: "cn=ldapuser, ou=users, o=services, dc=example, dc=com"
        bind_password: changeme
        user_search:
          base_dn: "dc=example,dc=com"
          attribute: cn
        group_search:
          base_dn: "dc=example,dc=com"
        files:
          role_mapping: "/mnt/elasticsearch/group_to_role_mapping.yml"
        unmapped_groups_as_roles: false
------------------------------------------------------------

===== LDAP Realm with User DN Templates
User DN templates can be specified if your LDAP environment uses a few specific standard naming conditions for users. The
advantage of this method is that a search is not needed to find the user DN; conversely the disadvantage is multiple bind
operations may be needed to find the right user DN. The following snippet shows an example of such configuration:

.Example LDAP Realm Configuration with User DN Templates
[source, yaml]
------------------------------------------------------------
shield:
  authc:
    realms:
      ldap1:
        type: ldap
        order: 0
        url: "ldaps://ldap.example.com:636"
        user_dn_templates:
          - "cn={0}, ou=users, o=marketing, dc=example, dc=com"
          - "cn={0}, ou=users, o=engineering, dc=example, dc=com"
        group_search:
          base_dn: "dc=example,dc=com"
        files:
          role_mapping: "/mnt/elasticsearch/group_to_role_mapping.yml"
        unmapped_groups_as_roles: false
------------------------------------------------------------

[[ldap-settings]]

.Common LDAP Realm Settings
|=======================
| Setting                        | Required | Description
| `type`                         | yes      | Indicates the realm type and must be set to `ldap`.
| `order`                        | no       | Indicates the priority of this realm within the realm chain. Realms with lower order will be consulted first. Although not required, it is highly recommended to explicitly set this value when multiple realms are configured. Defaults to `Integer.MAX_VALUE`.
| `enabled`                      | no       | Indicates whether this realm is enabled/disabled. Provides an easy way to disable realms in the chain without removing their configuration. Defaults to `true`.
| `url`                          | yes      | Specifies the LDAP URL in the form of `ldap[s]://<server>:<port>`. Shield attempts to authenticate against this URL.
| `group_search.base_dn`         | no       | Specifies a container DN to search for groups in which the user has membership. When this element is absent, Shield searches for a `memberOf` attribute set on the user in order to determine group membership.
| `group_search.scope`           | no       | Specifies whether the group search should be `sub_tree`, `one_level` or `base`.  `one_level` only searches objects directly contained within the `base_dn`. The default `sub_tree` searches all objects contained under `base_dn`. `base` specifies that the `base_dn` is a group object, and that it is the only group considered.
| `group_search.filter`          | no       | When not set, the realm will search for `group`, `groupOfNames`, or `groupOfUniqueNames`, with the attributes `member` or `memberOf`.  Any instance of `{0}` in the filter will be replaced by the user attribute defined in `group_search.user_attribute`
| `group_search.user_attribute`  | no       | Specifies the user attribute that will be fetched and provided as a parameter to the filter.  If not set, the user DN is passed into the filter.
| `unmapped_groups_as_roles`     | no       | When set to `true`, the names of any unmapped LDAP groups are used as role names and assigned to the user. The default value is `false`.
| `connect_timeout`              | no       | The timeout period for establishing an LDAP connection.  An `s` at the end indicates seconds, or `ms` indicates milliseconds. Defaults to "5s" - for 5 seconds
| `read_timeout`                 | no       | The timeout period for an LDAP operation.  An `s` at the end indicates seconds, or `ms` indicates milliseconds. Defaults to "5s" - for 5 seconds
| `files.role_mapping`           | no       | Specifies the <<ref-shield-files-location,location>> for the <<ldap-role-mapping, YAML role mapping configuration file>>. By default, it is `CONFIG_DIR/shield/role_mapping.yml`.
| `follow_referrals`             | no       | Boolean value that specifies whether Shield should follow referrals returned by the LDAP server. Referrals are URLs returned by the server that are to be used to continue the LDAP operation (e.g. search). Default is `true`.
| `hostname_verification`        | no       | When set to `true`, hostname verification will be performed when connecting to a LDAP server. The hostname or IP address used in the `url` must match one of the names in the certificate or the connection will not be allowed. Defaults to `true`.
| `cache.ttl`                    | no       | Specified the time-to-live for cached user entries (a user and its credentials will be cached for this configured period of time). Defaults to `20m` (use the standard Elasticsearch {ref}/common-options.html#time-units[time units]).
| `cache.max_users`              | no       | Specified the maximum number of user entries that can live in the cache at a given time. Defaults to 100,000.
| `cache.hash_algo`              | no       | (Expert Setting) Specifies the hashing algorithm that will be used for the in-memory cached user credentials (see <<ldap-cache-hash-algo,here>> for possible values).
|=======================

.User Template LDAP Realm Settings
|=======================
| Setting                        | Required | Description
| `user_dn_templates`            | yes      | Specifies the DN template that replaces the user name with the string `{0}`. This element is multivalued, allowing for multiple user contexts.
|=======================

.User Search LDAP Realm Settings added[1.1.0]
|=======================
| Setting                                  | Required | Description
| `bind_dn`                                | no       | The DN of the user that will be used to bind to the LDAP and perform searches. If this is not specified, an anonymous bind will be attempted.
| `bind_password`                          | no       | The password for the user that will be used to bind to the LDAP.
| `user_search.base_dn`                    | yes      | Specifies a container DN to search for users.
| `user_search.scope`                      | no       | The scope of the user search. Valid values are `sub_tree`, `one_level` or `base`. `one_level` only searches objects directly contained within the `base_dn`. The default `sub_tree` searches all objects contained under `base_dn`. `base` specifies that the `base_dn` is the user object, and that it is the only user considered.
| `user_search.attribute`                  | no       | The attribute to match with the username presented to Shield. The default attribute is `uid`
| `user_search.pool.size`                  | no       | The maximum number of connections to the LDAP server to allow in the connection pool. Default is `20`.
| `user_search.pool.initial_size`          | no       | The initial number of connections to create to the LDAP server on startup. Default is `5`.
| `user_search.pool.health_check.enabled`  | no       | Flag to enable or disable a health check on LDAP connections in the connection pool. Connections will be checked in the background at the specified interval. Default is `true`
| `user_search.pool.health_check.dn`       | no       | The distinguished name to be retrieved as part of the health check. Default is the value of `bind_dn`. If `bind_dn` is not specified, a value must be specified.
| `user_search.pool.health_check.interval` | no       | The interval to perform background checks of connections in the pool. Default is `60s`.
|=======================

NOTE:   If any settings starting with `user_search` are specified the `user_dn_templates` setting is ignored.

NOTE:   `bind_dn`, `bind_password` and `hostname_verification` are considered to be senstivie settings and therefore are not exposed via
        {ref}/cluster-nodes-info.html#cluster-nodes-info[nodes info API].

==== Adding an LDAP server certificate

To use SSL/TLS to access your LDAP server over an URL with the `ldaps` protocol, make sure the LDAP client used by 
Shield can access the certificate of the CA that signed the LDAP server's certificate. This enables Shield's LDAP 
client to authenticate the LDAP server before sending any passwords to it.

To do this, first obtain a certificate for the LDAP servers or a CA certificate that has signed the LDAP certificate.
You can use the `openssl` command to fetch the certificate and add the certificate to the `ldap.crt` file, as in
the following Unix example:

[source, shell]
----------------------------------------------------------------------------------------------
echo | openssl s_client -connect ldap.example.com:636 2>/dev/null | openssl x509 > ldap.crt
----------------------------------------------------------------------------------------------

NOTE: Older versions of openssl might not have the `-connect` option.  Instead use the `-host` and `-port` options.

[[keytool]]
This certificate needs to be stored in the node keystore/truststore. Import the certificate into the truststore with the
following command, providing the password for the keystore when prompted.

[source,shell]
----------------------------------------------------------------------------------------------------
keytool -import -keystore node01.jks -file ldap.crt
----------------------------------------------------------------------------------------------------

If not already configured, add the path of the keystore/truststore to `elasticsearch.yml` as described in <<securing-communications, Securing Communications with Encryption and IP Filtering>>.
By default, Shield will attempt to verify the hostname or IP address used in the `url` with the values in the
certificate. If the values in the certificate do not match, Shield will not allow a connection to the LDAP server. This
behavior can be disabled by setting the `hostname_verification` property.

Restart Elasticsearch to pick up the changes to `elasticsearch.yml`.

NOTE:   `hostname_verification` is considered to be a senstivie setting and therefore is not exposed via
        {ref}/cluster-nodes-info.html#cluster-nodes-info[nodes info API].

[[ldap-user-cache]]
==== User Cache

To avoid connecting to the LDAP server for every incoming request, the users and their credentials are cached
locally on each node. This is a common practice when authenticating against remote servers and as can be seen
in the table <<ldap-settings,above>>, the characteristics of this cache are configurable.

The cached user credentials are hashed in memory, and there are several hash algorithms to choose from:

[[ldap-cache-hash-algo]]

.Cache hash algorithms
|=======================
| Algorithm                       | Description
| `ssha256`                       | Uses a salted `SHA-256` algorithm (default).
| `md5`                           | Uses `MD5` algorithm.
| `sha1`                          | Uses `SHA1` algorithm.
| `bcrypt`                        | Uses `bcrypt` algorithm with salt generated in 10 rounds.
| `bcrypt4`                       | Uses `bcrypt` algorithm with salt generated in 4 rounds.
| `bcrypt5`                       | Uses `bcrypt` algorithm with salt generated in 5 rounds.
| `bcrypt6`                       | Uses `bcrypt` algorithm with salt generated in 6 rounds.
| `bcrypt7`                       | Uses `bcrypt` algorithm with salt generated in 7 rounds.
| `bcrypt8`                       | Uses `bcrypt` algorithm with salt generated in 8 rounds.
| `bcrypt9`                       | Uses `bcrypt` algorithm with salt generated in 9 rounds.
| `sha2`                          | Uses `SHA2` algorithm.
| `apr1`                          | Uses `apr1` algorithm (md5 crypt).
| `noop`,`clear_text`             | Doesn't hash the credentials and keeps it in clear text in memory. CAUTION:
                                    keeping clear text is considered insecure and can be compromised at the OS
                                    level (e.g. memory dumps and `ptrace`).
|=======================

===== Cache Eviction API

Shield exposes an API to force cached user eviction. The following example, evicts all users from the `ldap1`
realm:

[source, java]
------------------------------------------------------------
$ curl -XPOST 'http://localhost:9200/_shield/realm/ldap1/_cache/clear'
------------------------------------------------------------

It is also possible to evict specific users:

[source, java]
------------------------------------------------------------
$ curl -XPOST 'http://localhost:9200/_shield/realm/ldap1/_cache/clear?usernames=rdeniro,alpacino'
------------------------------------------------------------

Multiple realms can also be specified using comma-delimited list:

[source, java]
------------------------------------------------------------
$ curl -XPOST 'http://localhost:9200/_shield/realm/ldap1,ldap2/_cache/clear'
------------------------------------------------------------
