=====================================
Enabling TLS on LDAP/Active Directory
=====================================


To enable a secure Transport Layer Security (TLS) connection on
LDAP/Active Directory, add the following to the LDAP configuration
section of the file ``$PREFIX/etc/anaconda-server/config.yaml``::

    LDAP:
      ...  # Rest of the LDAP config
      START_TLS: true,
      OPTIONS:
        OPT_PROTOCOL_VERSION: 3
        OPT_X_TLS_DEMAND: true
        OPT_X_TLS_REQUIRE_CERT: 'OPT_X_TLS_NEVER'
        OPT_X_TLS_CACERTFILE: '/path/to/certfile'

NOTE: Replace ``/path/to/certfile`` with the actual path to certfile.

If you're using self-signed certificates you'll need to add
``OPT_X_TLS_NEWCTX`` as the **last entry** of the ``OPTIONS`` field
of the ``LDAP`` options::

    LDAP:
      ...  # Rest of the LDAP config
      START_TLS: true,
      OPTIONS:
        OPT_PROTOCOL_VERSION: 3
        OPT_X_TLS_DEMAND: true
        OPT_X_TLS_REQUIRE_CERT: 'OPT_X_TLS_NEVER'
        OPT_X_TLS_CACERTFILE: '/path/to/certfile'
        OPT_X_TLS_NEWCTX: 0


.. _ldap-configuration-options:

Using LDAP and TLS configuration options
========================================

URI
---

Start by setting URI to point to your server. The value of this
setting can be anything that your LDAP library supports. For instance,
``openldap`` may allow you to give a comma- or space-separated list of
URI values to try in sequence.

BIND_DN
-------

The distinguished name to use when binding to the LDAP server
with BIND_AUTH. Use the empty string---the default---for an
anonymous bind.

BIND_AUTH
---------

The password to use with BIND_DN.

USER_SEARCH
-----------

A dictionary that locates a user in the directory. The dict object must
contain the required entries ``base`` and ``filter`` and may contain
the optional entry ``scope``.

* base: The base DN to search.

* filter: Should contain the placeholder ``%(username)s`` for the
  username.

* scope: One of ``LDAP_SCOPE_BASE``, ``LDAP_SCOPE_ONELEVEL`` or
  ``LDAP_SCOPE_SUBTREE``.

EXAMPLE:

.. code-block:: yaml

    {'base': 'dc=example,dc=com', 'filter': 'uid=%(username)s'}

SUPERUSER_SEARCH
----------------

A dict that will determine whether a valid user is a superuser. The dict object must contain
the required entries ``base`` and ``filter`` and may contain the optional entry
``scope``. If the search is successful, then something is returned by the LDAP server, and the user is
given superuser permissions.

* base: The base DN to search.
* filter: Should contain the placeholder ``%(username)s`` for the username.
* scope: One of ``LDAP_SCOPE_BASE``, ``LDAP_SCOPE_ONELEVEL``, or ``LDAP_SCOPE_SUBTREE``.

For example:

.. code-block:: yaml

    {'base': 'cn=admin,ou=Groups,dc=example,dc=com', 'filter': 'memberUid=%(username)s'}

Notice that this check is done during the login procedure, so even though privileges might have
been removed from (or added to) the LDAP server, the user will have to authenticate again to see
the changes.

ENABLE_GROUPS
-------------

This attribute enables LDAP group synchronization, allowing users to
synchronize group membership with an LDAP directory. Defaults to
``false``.

EXAMPLE:

.. code-block:: yaml

    ENABLE_GROUPS: true

.. _tls-group-search:

GROUP_SEARCH
------------

A dictionary that locates a group in the directory. An LDAP
search is performed using the ``base`` distinguished name and
``filter``.

EXAMPLE:

.. code-block:: yaml

    GROUP_SEARCH:
        base: dc=example,dc=com
        filter: (objectClass=group)

NOTE: Anaconda Repository assumes that the groups' `objectClass`
is `groupOfNames` (or a compatible schema). The following
`LDIF <https://en.wikipedia.org/wiki/LDAP_Data_Interchange_Format>`_
snippet shows an example group instance:

.. code-block:: none

    dn: cn=Analysts,ou=Anaconda Groups,dc=example,dc=com
    cn: Analysts
    member: cn=John Doe,ou=Users,dc=example,dc=com
    member: cn=Jane Doe,ou=Users,dc=example,dc=com
    member: cn=John Q. Public,ou=Users,dc=example,dc=com
    member: cn=Guy Incognito,ou=Users,dc=example,dc=com
    objectclass: groupOfNames
    objectclass: top


GROUP_MEMBERS_ATTR
------------------

The LDAP attribute on a group object that indicates the users that are
members of the group. Defaults to ``member``.

EXAMPLE:

.. code-block:: yaml

    GROUP_MEMBERS_ATTR: 'member'

NOTE: Anaconda Repository assumes that the groups' `objectClass`
is `groupOfNames` (or a compatible schema).

REFRESH_INTERVAL
----------------

The number of seconds that group membership information from LDAP is
used before being fetched from the directory server again. Defaults
to ``3600``, which is 1 hour.

EXAMPLE:

.. code-block:: yaml

    REFRESH_INTERVAL: 600


KEY_MAP
-------

This is a dict mapping application context to LDAP. An application may
expect user data to be consistent, and not all LDAP setups use the same
configuration:

.. code-block:: yaml

    'application_key': 'ldap_key'

EXAMPLE:

.. code-block:: none

    KEY_MAP={'name': 'cn', 'company': 'o', 'email': 'mail'}

START_TLS
---------

If ``true``, each connection to the LDAP server calls
``start_tls_s()`` to enable TLS encryption over the standard LDAP
port. There are a number of configuration options that can be given
to OPTIONS that affect the TLS connection. For example,
OPT_X_TLS_REQUIRE_CERT can be set to ``OPT_X_TLS_NEVER`` to
disable certificate verification, perhaps to allow self-signed
certificates.

OPTIONS
-------

This stores LDAP specific options.

EXAMPLE:

.. code-block:: yaml

    LDAP:
        OPTIONS:
            OPT_PROTOCOL_VERSION: 3
            OPT_X_TLS_REQUIRE_CERT: 'OPT_X_TLS_NEVER'

TLS---secure LDAP
-----------------

To enable a secure TLS connection you must set START_TLS to
``true``. There are a number of configuration options for OPTIONS
that affect the TLS connection.

EXAMPLE: OPT_X_TLS_REQUIRE_CERT set to ``OPT_X_TLS_NEVER``
disables certificate verification, perhaps to allow self-signed
certificates:

.. code-block:: yaml

    LDAP:
        START_TLS: true
        OPTIONS:
            OPT_PROTOCOL_VERSION: 3
            OPT_X_TLS_DEMAND: true
            OPT_X_TLS_REQUIRE_CERT: 'OPT_X_TLS_NEVER'
            OPT_X_TLS_CACERTFILE: '/path/to/certfile'
