> ## Documentation Index
> Fetch the complete documentation index at: https://docs.xorlab.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> Pages under /latest/ document the current release. Paths that begin with a version number, for example /10.0/, are frozen snapshots of superseded releases kept for reference only — never present their instructions as current. If the reader's version is unknown, answer from /latest/ and say which version the answer describes.
> xorlab is deployed on-premises, hybrid, or as a cloud service, and integrates with either Microsoft 365 or on-premises mail infrastructure. Configuration steps often differ between these. State which deployment and integration mode an instruction applies to instead of presenting one as universal.
> Distinguish inline mode from monitoring mode when describing anything that acts on email. Monitoring mode observes a copy and cannot block or quarantine; inline mode routes mail through xorlab and can.
> Write the product name as lowercase 'xorlab'. Use the documented component names: xorlab Control Center (XCC), xorlab MTA, xorlab Sandbox (DANA), xorlab Natural Language Understanding (NLU). After the first mention, use the short forms XCC, MTA, Sandbox, and NLU. Do not use DANA as a standalone name for the Sandbox, but keep it where it is a literal string in configuration keys, container names, and hostnames.
> Do not invent configuration keys, rule parameters, list names, log properties, or API fields. If a value is not present in this documentation, say that it is not documented rather than guessing.

# Enable LDAP Login

> Configure the LDAP backend so users sign in to xorlab with their existing directory credentials.

<Warning>
  **Prerequisites**

  * If you want to connect to an LDAP server with non-public certificates, follow [Add Trusted CA Certificates](/latest/authentication-certificates).
</Warning>

## Basic configuration

LDAP backend is defined in the `ldapAuthDataSources:` subsection of the `usernamePasswordAuthBackends:` section in the `auth/auth/auth.yml` file. First, you have to set up the basic parameters of your LDAP source, starting with its name—that can be whatever you like (`myLDAP` in this sample case)—and then configuring the connection as in the example below:

```yaml auth.yml theme={null}
    ldapAuthDataSources:
      myLDAP:
        host: ldap.example.com
        port: 10636
        useLdaps: true
        useStartTls: false
        trustAll: false
```

The following table explains the parameters:

| Parameter     | Value                                                                                        |
| :------------ | :------------------------------------------------------------------------------------------- |
| `host`        | Address of your LDAP server                                                                  |
| `port`        | Port number of your LDAP server                                                              |
| `useLdaps`    | Whether to use SSL on the socket layer (conflicts with `startTls` below)                     |
| `useStartTls` | Whether to use the `startTLS` command (conflicts with `useLdaps` above)                      |
| `trustAll`    | Skip verification of the SSL server certificate (**warning**: do NOT do this on production!) |

## Authentication

The next step involves user authentication in your LDAP server. You can use a direct distinguished name (DN) of a user who is being authenticated (if you already know what the DN of a user looks like) or query LDAP for the DN. Either way, you have to specify only one method.

This is done within the `authentication:` subsection of your LDAP server configuration.

### Direct DN

If you want to use a direct DN of a user, you just set the `withUserDn.userDnPattern` attribute to a pattern which will allow to deduct a DN from a login username string, e.g., `"uid={0},ou=users,dc=company,dc=com"`, where `{0}` will be substituted with a username:

```yaml auth.yml theme={null}
        authentication:
          withUserDn:
            userDnPattern: "uid={0},ou=users,dc=example,dc=com"
```

### DN query

When a DN of a user is not known, you can search the LDAP directory for the user entry using a so-called *technical user* for authentication. Once the user entry is found, their DN is used to authenticate with the provided credentials.

A sample configuration of a DN query is as follows:

```yaml auth.yml theme={null}
        authentication:
          withQueryDn:
            bindDn: "uid=xcc-dev,ou=users,dc=example,dc=com"
            bindPassword: "LDAP_bind_pw"
            userBase: "ou=users,dc=example,dc=com"
            userSearch: "(uid={0})"
```

The table below explains the parameters:

| Parameter      | Value                                                                                                                                                                                               |
| :------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `bindDn`       | The bind DN of the technical user that will be used to fetch the user information from the directory; both user and password can be omitted if the directory supports unauthenticated access        |
| `bindPassword` | Password for the technical user                                                                                                                                                                     |
| `userBase`     | Specifies the subtree in the directory where user information is stored                                                                                                                             |
| `userSearch`   | Template for user search query, e.g., <br />- for OpenLDAP: `"(cn={0})"`<br />- for Microsoft Active Directory: `"(sAMAccountName={0})"`<br /> where `{0}` will be replaced with the login username |

## Authorization

After a successful authentication, a user has to be authorized: their roles are read from the LDAP backend. In the `authorization.query:` subsection, you can configure the parameters of the role search using a nested search within a subtree of a directory as in the sample configuration below:

```yaml auth.yml theme={null}
        authorization:
          query:
            roleBase: "ou=groups,dc=example,dc=com"
            roleSearch: "(member={0})"
            nestedRoleDepth: 2
            groupRoleAttribute: dn
```

The parameters are explained in the table below:

| Parameter            | Value                                                                                                                                                                     |
| :------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `roleBase`           | Base of the role subtree                                                                                                                                                  |
| `roleSearch`         | Filter to search for roles where<br />- `{0}` is substituted with the DN of the user entry found with the prior user search<br />- `{1}` is substituted with the username |
| `nestedRoleDepth`    | Integer that specifies how many times to search the directory for nested roles (set to `0` to disable resolution of nested roles)                                         |
| `groupRoleAttribute` | The role name to be used as an input for the `roleMapping` attribute; if this is not set, the DN of the role entry is used                                                |

## Attribute mapping

In the next step you have to map (assign) attributes from the LDAP user entries to the user model in xorlab Security Platform. The mapping is described using [Spring expression language](https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/expressions.html) and is configured under the `attributeMapping:` subsection.

You can use these methods:

* `attr('<name>')`: retrieve the attribute with the `'<name>'` name from attributes in the source authorization system
* `replace(<string or list of strings>, '<pattern>', 'replace')`: replace every occurrence of `'<pattern>'` with `'replace'` in an input string or a list of input strings
* `azureAdEmails()`: read all email addresses from the Azure Active Directory `proxyAddresses` attribute.

Literal values have to be quoted, e.g., `key: 'literal value'`.

A sample configuration for attribute mapping, which simply retrieves attributes from the auth system, would look like this:

```yaml auth.yml theme={null}
        attributeMapping:
          userName: "attr('uid')"
          displayName: "attr('cn')"
          emails: "attr('mail')"
```

Available attributes are explained in the table below:

| Attribute     | Description                                                                                                                                                                      |
| :------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `userName`    | An attribute mapping for the username. The result of this mapping will be put into the `subject` attribute of the token issued to the consuming services                         |
| `displayName` | An attribute mapping for the display name of the user. It is optional and could be used by consuming services in places where a more descriptive name of the user is appreciated |
| `emails`      | A mapping for the list of emails associated with the user. Consuming services might use this list to associate the user with a certain pool of email messages                    |
| `tenant`      | **Only required for multi-tenancy deployments**: Make sure the value of the `tenant` attribute correspond to the `name` defined in the `guarded_tenants.yml`.                    |

## Role mapping

The last step is to configure role mapping. You must map all roles served by the LDAP directory to the corresponding xorlab roles under the `roleMapping:` subsection. Roles that are not mapped are ignored by default. Multiple xorlab roles can be mapped to the same LDAP role, e.g., `xcc_login` → `company1-group1`, `xcc_admin` → `company1-group1`.

<Note>
  The role mapping is case sensitive, therefore make sure that you specify the role names according to what is served by the LDAP directory.
</Note>

A sample role mapping configuration is shown below:

```yaml auth.yml theme={null}
        roleMapping:
          xcc_login: [ "cn=dev_xcc_login,ou=groups,dc=example,dc=com" ]
          xcc_analyst: [ "cn=dev_xcc_login,ou=groups,dc=example,dc=com" ]
          xcc_admin: [ "cn=dev_xcc_soc_admin,ou=groups,dc=example,dc=com" ]
          xcc_insights: [ "cn=dev_xcc_login,ou=groups,dc=example,dc=com" ]
          xcc_monitor: [ "cn=dev_xcc_soc_admin,ou=groups,dc=example,dc=com" ]
```

If the LDAP directory already serves roles compatible with xorlab (see [Built-in Roles](/latest/built-in-user-roles)), you can also specify a “pass-through” role-mapping mode using `roleMappingMode: PASS_THROUGH`.

<Note>
  Please be aware that in the pass-through role-mapping mode, all roles served by the LDAP directory are added to the xorlab authorization context. If this context is becoming too large, i.e., too many irrelevant roles are added, then it might lead to errors and users being unable to access XCC. Therefore, it is advisable to only map the roles that are relevant to xorlab.
</Note>

A sample role mapping configuration using the pass-through mode:

```yaml auth.yml theme={null}
        roleMappingMode: PASS_THROUGH
        roleMapping:
          # You can still define a role mapping in pass-through mode
          xcc_monitor: [ "cn=dev_xcc_soc_admin,ou=groups,dc=example,dc=com" ]
```

## Activate the configuration

After updating `auth/auth/auth.yml`, click **Publish**. The authentication configuration becomes active within about one minute.

## Multi-Tenancy

The setup on this page applies unchanged in a multi-tenant deployment. Two things are added on top: a `tenant` entry in the [Attribute mapping](#attribute-mapping) that matches the tenant `name` in `guarded_tenants.yml`, and a [tenant-restricted user role](/latest/built-in-user-roles) in the [Role mapping](#role-mapping).

<Card title="Enable Tenant Login" icon="building" horizontal href="/latest/multi-tenancy-authentication#ldap-login">
  Complete per-tenant LDAP example, and the other login options available to tenants.
</Card>

## Example configuration

The final configuration for an LDAP backend should look like this:

```yaml auth.yml theme={null}
tokenSigningKey: "xyz"

enabledAuthBackends:
  - usernamePassword

usernamePasswordAuthBackends:
  usernamePassword:
    ldapAuthDataSources:
      myLDAP:
        host: ldap.example.com
        port: 10636
        authentication:
          withQueryDn:
            bindDn: "uid=xcc-dev,ou=users,dc=example,dc=com"
            bindPassword: "LDAP_bind_pw"
            userBase: "ou=users,dc=example,dc=com"
            userSearch: "(uid={0})"
        authorization:
          query:
            roleBase: "ou=groups,dc=example,dc=com"
            roleSearch: "(member={0})"
            nestedRoleDepth: 2
        attributeMapping:
          userName: "attr('uid')"
          displayName: "attr('cn')"
          emails: "attr('mail')"
        roleMapping:
          xcc_login: [ "cn=dev_xcc_login,ou=groups,dc=example,dc=com" ]
          xcc_analyst: [ "cn=dev_xcc_login,ou=groups,dc=example,dc=com" ]
          xcc_admin: [ "cn=dev_xcc_soc_admin,ou=groups,dc=example,dc=com" ]
          xcc_insights: [ "cn=dev_xcc_login,ou=groups,dc=example,dc=com" ]
          xcc_monitor: [ "cn=dev_xcc_soc_admin,ou=groups,dc=example,dc=com" ]
```
