> ## 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.

# LDAP-based Authentication

xorlab Authentication Service needs search and read access through the LDAP interface to verify user credentials. The connection to an LDAP server requires a [custom certificate in a trust store](/9.0/authentication#certificate-configuration).

<Note>
  Before you start configuring this backend, please read the *[Authentication](/9.0/authentication)* article, if you haven’t already.
</Note>

## 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 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 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 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 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 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 `authTenantId` 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 XSP roles under the `roleMapping:` subsection. Roles that are not mapped are ignored by default. Multiple XSP 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 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 Security Platform (see *[Users, Roles, and Permissions](/9.0/users-roles-and-permissions)*), you can also specify a “pass-through” role-mapping mode using `roleMappingMode: PASS_THROUGH` (note that this was the default behavior before XSP 7.0).

<Note>
  Please be aware that in the pass-through role-mapping mode, all roles served by the LDAP directory are added to the XSP 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 XSP.
</Note>

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

```yaml 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" ]
```

## Multi-Tenant Configuration

Please follow the instructions on this page to setup LDAP-based Authentication in a multi-tenancy deployment. Make to include the `tenant` property in the [Attribute Mapping](#attribute-mapping) configuration and that its value is a one-on-one match with the `authTenantId` property specified in the [Multi-Tenancy Configuration](/9.0/multi-tenancy-configuration). For `roleMapping`, make sure to map to a [tenant-restricted user roles](users-roles-and-permissions.md/#roles).

```yaml theme={null}
    attributeMapping:
      userName: "attr('uid')"
      displayName: "attr('cn')"
      emails: "attr('mail')"
      tenant: tenantA # should correspond to authTenantId in guarded_tenants.yml
    RoleMapping:
      xcc_tenant_analyst: [ "cn=dev_xcc_login,ou=groups,dc=example,dc=com" ]
      xcc_tenant_analyst_audit: [ "cn=dev_xcc_login,ou=groups,dc=example,dc=com" ]
```

## Example configuration

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

```yaml theme={null}
tokenSigningKey: "xyz"

enabledAuthBackends:
  - usernamePassword

usernamePasswordAuthBackends:
  usernamePassword:
    enabledAuthDataSources:
      - myLDAP
      
    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" ]
```
