LDAP

When using an LDAP datasource, the hostname and port must be configured, as well as an indication whether the connection is an LDAPS connection or a regular ldap connection. When it’s LDAPS, there are TLS-settings available to specify acceptable server certificates, as well as reference they key material that can be used for client authentication. It is possible to indicate that an LDAP server is Microsoft Active Directory by setting the ldap-server-type configuration option to active-directory.

Note

When configuring a datasource as active-directory, there are specific settings that will be applied. For one, an Active Directory schema will be used to find and store account-related attributes (i.e. sAMAccountName is used to represent an accountId, userAccountControl is used to enable or disable accounts, users are created with user objectClass, etc.). Also, when password modification is enabled, the strategy to store passwords will use a specific way that Active Directory requires (i.e. target the unicodePwd-attribute with the correct encoding).

By default, LDAP connections are managed in a connection pool. The connection pool behaviour can be tweaked to adjust for the environment and usage of the server. The details of how the connection pool works and how to configure it are described below.

Connections to the LDAP datasource can be based on anonymous binding, or alternatively use a client-id and client-secret to specify the administrative account to use for binding to the LDAP server.

Hint

Use the full qualified directory entry name to indicate the client_id, i.e. cn=Directory Admin,dc=curity,dc=se.

To search the directory, a default root must be specified that is used to base searches on. Each search is then performed using a sub scope. You can change the search scope in the configuration . Please see the configuration of LDAP for more on the available options.

The LDAP datasource can be used for different purposes. It applies default settings based on the server-type or the server-type’s schema. There is one filter that needs to be explicitly configured though, which is the search-filter-account-id query. This filter is used to find an account entry, based on the configured default-root of the directory tree. If there are no special conditions, this setting could be configured like (uid={}).

Note that an attribute provider can override the search-filter-account-id by explicitly configuring the search-filter in the account section of the data-source configuration.

Search filters are standard LDAP search filters, which are specified through RFC 4515. Each search-filter can take an argument, which is documented along the configuration option in the reference. This argument is substituted for the {}-placeholder of the configured search-filter. Examples are (uid={}), (&(phoneNumber={})(objectClass=inetOrgPerson)), etc. Note that you can write a filter without brackets, if it contains a single predicate, for example uid={} is a valid search-filter and is the same as (uid={}).

When a search query for an account or for an attribute-provider returns many attributes that are not needed or used, it is possible to configure a whitelist of attributes that is sent with the request to the LDAP server. The LDAP server can use this whitelist when sending back a response. This whitelist can be independently configured for an account provider as well as for an attribute provider, by adding adding the attribute names to the ldap-attribute-to-fetch setting. If no attribute names are configured, the LDAP server is expected to return all attributes as part of the response.

LDAP for Account and Credential Data Access

In case the LDAP datasource is used to access account-information (i.e. see Account Manager), or as authentication backend (i.e. through a Credential Manager), the default configuration only requires configuring search-filter-account-id. When needed, it is possible to override default search-filters for account-related queries that are based on email-address or phone-number.

The account-id-attribute is an optional configuration setting that you can use to specifically set the attribute that represents the Account Identifier, the unique id of the account. In case this is not configured, the value of the EntryDN is used for this.

Account Status

Each account has a status that indicates whether an account is enabled or not. One place where this is used, is through the self service registration procedure, which can enforce a workflow where an account needs to be activated through email or phone number verification.

In case of a generic ldap-server-type, the InetOrgPerson schema is used. This does not define default attributes for holding this property, so an existing attribute is “repurposed” to store this information. By default, the carLicense attribute is used for this. If this collides somehow, it is possible to configure an alternative LDAP attribute for this purpose, by setting the active-state-attribute value in the account section of the LDAP datasource configuration. In case of Active Directory however, there exists an attribute to manage account status. The userAccountControl attribute holds multiple flags of the user account. The Curity Identity Server will use this attribute to test whether an account is active or not (by testing the enabled flag). In case an account is activated (i.e. an e-mail address is confirmed, etc.), the AccountManager will overwrite the userAccountControl value such that it represents an enabled and normal user.

It is also possible to configure the value that indicates that an account is active. Typically, this is not needed; however, if the attribute that is defined is not a Boolean value, then it probably is. For instance, the attribute that holds the active state could be something like customerState. This can be handled by changing the active-state-attribute, but suppose that accounts are active when this attribute has the string value ACTIVE. In such a case, the active-state-attribute-value can be set to this non-Boolean value. Whenever an account’s activation state is checked, a case-insensitive comparison to this configured value will be performed. If the values are equal, then the account will be considered active. For the same use case, it is also possible to configure the value the represents the inactive state. Configuring this makes sure that Curity Identity Server sets the correct value when creating or disabling accounts.

Phone number and email

The mobile phone number is used when authenticating using the SMS authenticator. The default location used to retrieve the number is telephoneNumber. If that is not where the mobile phone number is stored this can be updated in the config.

The same exists for the email. If it is not stored in the regular mail location, it also needs to be remapped if the operations involving emails, such as reset password, activate account and login using email hyperlink are to work.

Example of remapping email and phone:

Listing 43 Active Directory LDAP data-source with email and phone remapped
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    <data-source>
      <id>ActiveDirectoryUserstore</id>
      <ldap xmlns="https://curity.se/ns/conf/data-access/ldap">
        <hostname>ldap.curity.se</hostname>
        <port>636</port>
        <ldaps>true</ldaps>
        <tls>
          <disable-hostname-verification>false</disable-hostname-verification>
          <use-truststore>true</use-truststore>
        </tls>
        <client-id>cn=Directory Manager,ou=admins,dc=curity,dc=se</client-id>
        <client-secret>password</client-secret>
        <ldap-server-type>active-directory</ldap-server-type>
        <default-root>ou=Users,dc=curity,dc=se</default-root>
        <account>
          <search-filter-account-id>sAMAccountName={}</search-filter-account-id>
          <ldap-attribute-to-fetch>name</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>email</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>mobile</ldap-attribute-to-fetch>
          <mobile-phone-number-attribute>mobile</mobile-phone-number-attribute>
          <email-attribute>email</email-attribute>
        </account>
      </ldap>
    </data-source>

Credential Management

An LDAP datasource can also be used to both verify as well as perform basic credential management. The procedure of verifying credentials, authentication, is based on a two step process. The first step will take a username, and try to find the EntryDN for that username (using the search-filter-account-id query). The second step will perform a bind-operation, that uses the EntryDN that was found in the first step, and a provided password. When both steps succeed, authentication will be successful. The data source also checks the account status, failing the credential verification for inactive accounts.

Apart from using LDAP to verify credentials, it is also possible to manage password. This is done through either an attribute replacement strategy or a modify password strategy. Which one to choose, depends completely on the particular LDAP server that is used. In case the ldap-server-type is set to active-directory, the strategy is to update the unicodePwd attribute using the encoding that is used by Active Directory, no further configuration is necessary. If ldap-server-type is generic, the default option is to try the modify password strategy. Because this is using the ModifyPassword LDAPv3 extended operation, not every LDAP server will support this. If that’s the case, the credentials section of the LDAP datasource allows you to explicitly indicate that the attribute replacement strategy must be used. The format in which the password attribute must be encoded, can be set through the password-encoding setting. The attribute will always be userPassword, which follows from the InetOrgPerson schema.

When an LDAP datasource is used by a Credential Manager, it is possible to configure a whitelist of attributes to retrieve as part of a query for verifying credentials (using the attributes-to-fetch configuration setting for the credentials part of the LDAP datasource). Using this, it is possible to control the attributes that are included in the authenticated user’s attributes as a result of authentication.

Note

The password-encoding settings that are available, are commonly used by LDAP server implementations. However, there is no guarantee that your LDAP server supports anything other than plaintext. Please see the particular LDAP server documentation to learn more about what your LDAP server supports.

Warning

It is possible to configure an Active Directory to allow for unauthenticated binds, and in some versions it is also the default behavior. This means that it would be possible for a user to be logged in without providing a password. Curity Identity Server mitigates this in built-in plugins by disallowing password fields to be sent without a value, but custom plugins needs to have this validation in place. To be safe, configure your Active Directory to disable unauthenticated binds. In Windows Server 2019 this is done by adding an attribute msDS-Other-Settings with the value DenyUnauthenticatedBind=1 to the object CN=Directory Service, CN=Windows NT, CN=Services, CN=Configuration

Active Directory: User must change password at next logon

Specific for Active Directory, there is support for handling a bind response when the User must change password at next logon flag is set on the user’s account in Active Directory. Detecting this flag in Curity Identity Server can be enabled in the configuration of the LDAP DataSource through the Detect User Must Reset Password option (by default it is disabled). If the UserMustResetPassword flag was set for the user’s account, then the _userMustResetPassword attribute is included in the SubjectAttributes of the resulting Authentication Attributes. To respect this flag, the admin _must_ manually add a Reset Password Authentication Action to trigger a password reset, and use the _userMustResetPassword attribute to detect the intent to reset the password. This feature is specific for Active Directory only.

Example configuration

The following configuration defines a generic LDAP data source with a whitelist for the account attributes that are retrieved for an Account Manager.

Listing 44 Generic LDAP data-source with attribute whitelist configuration example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    <data-source>
      <id>LdapUserstore</id>
      <ldap xmlns="https://curity.se/ns/conf/data-access/ldap">
        <hostname>ldap.curity.se</hostname>
        <port>6636</port>
        <ldaps>true</ldaps>
        <tls>
          <disable-hostname-verification>true</disable-hostname-verification>
          <use-truststore>true</use-truststore>
        </tls>
        <client-id>cn=Directory Manager,ou=admins,dc=curity,dc=se</client-id>
        <client-secret>password</client-secret>
        <default-root>ou=People,dc=curity,dc=se</default-root>
        <account>
          <search-filter-account-id>uid={}</search-filter-account-id>
          <ldap-attribute-to-fetch>cn</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>sn</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>mail</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>telephoneNumber</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>description</ldap-attribute-to-fetch>
        </account>
      </ldap>
    </data-source>

The following configuration defines an Active Directory LDAP data source with a whitelist for the account attributes that are retrieved for an Account Manager. If this datasource is also used for storing credentials, the unicodePwd attribute is used on entries found in ou=Users,dc=curity,dc=se.

Listing 45 Active Directory LDAP data-source with attribute whitelist configuration example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
    <data-source>
      <id>ActiveDirectoryUserstore</id>
      <ldap xmlns="https://curity.se/ns/conf/data-access/ldap">
        <hostname>ldap.curity.se</hostname>
        <port>636</port>
        <ldaps>true</ldaps>
        <tls>
          <disable-hostname-verification>true</disable-hostname-verification>
          <use-truststore>true</use-truststore>
        </tls>
        <client-id>cn=Directory Manager,ou=admins,dc=curity,dc=se</client-id>
        <client-secret>password</client-secret>
        <ldap-server-type>active-directory</ldap-server-type>
        <default-root>ou=Users,dc=curity,dc=se</default-root>
        <account>
          <search-filter-account-id>sAMAccountName={}</search-filter-account-id>
          <ldap-attribute-to-fetch>name</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>mail</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>telephoneNumber</ldap-attribute-to-fetch>
        </account>
      </ldap>
    </data-source>

The following configuration defines a generic LDAP data source, and includes specific configuration that defines that when storing a password, it should be saved to userPassword, as plaintext value.

Listing 46 Generic LDAP data-source with credential management configuration
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    <data-source>
      <id>LdapUserstore</id>
      <ldap xmlns="https://curity.se/ns/conf/data-access/ldap">
        <hostname>ldap.curity.se</hostname>
        <port>6636</port>
        <ldaps>true</ldaps>
        <tls>
          <disable-hostname-verification>true</disable-hostname-verification>
          <use-truststore>true</use-truststore>
        </tls>
        <client-id>cn=Directory Manager,ou=admins,dc=curity,dc=se</client-id>
        <client-secret>password</client-secret>
        <default-root>ou=People,dc=curity,dc=se</default-root>
        <account>
          <search-filter-account-id>uid={}</search-filter-account-id>
          <ldap-attribute-to-fetch>cn</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>sn</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>mail</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>telephoneNumber</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>description</ldap-attribute-to-fetch>
        </account>
        <credentials>
          <use-attribute-replacement>
            <password-encoding>plaintext</password-encoding>
          </use-attribute-replacement>
        </credentials>
      </ldap>
    </data-source>

LDAP for Attribute Data Access

The LDAP datasource can be used as Attribute Provider. By default, all the attributes that the LDAP server returns as part of executing the search-filter-account-id query will be made available. It is however possible for attribute providers to override both that query as well as the whitelist of attributes to request, The following example does just that.

Example configuration

Listing 47 Generic LDAP data-source with attribute configuration override example
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    <data-source>
      <id>LdapAttributeStore</id>
      <ldap xmlns="https://curity.se/ns/conf/data-access/ldap">
        <hostname>ldap.curity.se</hostname>
        <port>6636</port>
        <ldaps>true</ldaps>
        <tls>
          <disable-hostname-verification>true</disable-hostname-verification>
          <use-truststore>true</use-truststore>
        </tls>
        <client-id>cn=Directory Manager,ou=admins,dc=curity,dc=se</client-id>
        <client-secret>password</client-secret>
        <default-root>ou=Attributes,dc=curity,dc=se</default-root>
        <search-scope>sub</search-scope>
        <account>
          <search-filter-account-id>uid={}</search-filter-account-id>
        </account>
        <attributes>
          <search-filter>(&amp;(uid={})(memberof=CN=employees,OU=groups,dc=curity,dc=se))</search-filter>
          <ldap-attribute-to-fetch>carLicense</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>roomNumber</ldap-attribute-to-fetch>
        </attributes>
      </ldap>
    </data-source>

Use-case for configuring an LDAP backend for HTML Forms authenticator

One way to use the LDAP backend is for user authentication. To achieve this, multiple parts of the system need to be configured to work together. The following diagram presents a high level perspective on the resulting system.

../../_images/ldap-for-htmlform-authentication-overview.png

To configure the whole system, use the following order:

  1. Setup the LDAP datasource
  2. Create the Credential Manager for the LDAP datasource
  3. Create an Account Manager with the Credential Manager
  4. Create the HTML Form authenticator, that uses the Account Manager
  5. Enable the authenticator for Service Providers (or Clients)

Setup the LDAP datasource

The way to setup the LDAP datasource is discussed in the LDAP section above. You will need some settings regarding how to connect to the LDAP backend, as well as the location of the users in the directory.

Example configuration in /facilities/data-sources :

Listing 48 LDAP data-source configuration for HTML forms authenticator using LDAP use-case
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    <data-source>
      <id>LdapUserstore</id>
      <ldap xmlns="https://curity.se/ns/conf/data-access/ldap">
        <hostname>ldap.curity.se</hostname>
        <port>6636</port>
        <ldaps>true</ldaps>
        <tls>
          <disable-hostname-verification>true</disable-hostname-verification>
          <use-truststore>true</use-truststore>
        </tls>
        <client-id>cn=Directory Manager,ou=admins,dc=curity,dc=se</client-id>
        <client-secret>password</client-secret>
        <default-root>ou=People,dc=curity,dc=se</default-root>
        <search-scope>sub</search-scope>
        <account>
          <search-filter-account-id>uid={}</search-filter-account-id>
          <ldap-attribute-to-fetch>cn</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>sn</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>mail</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>telephoneNumber</ldap-attribute-to-fetch>
          <ldap-attribute-to-fetch>description</ldap-attribute-to-fetch>
        </account>
      </ldap>
    </data-source>

Create the Credential Manager for the LDAP datasource

A Credential Manager is always configured with a data-source. For more on configuring a Credential Manager, see Credential-manager.

Example configuration in /processing/credential-managers :

Listing 49 Credential Manager configuration for HTML forms authenticator using LDAP use-case
1
2
3
4
5
6
    <credential-manager>
      <id>LdapCredentialManager</id>
      <data-source-backed>
        <data-source-id>LdapUserstore</data-source-id>
      </data-source-backed>
    </credential-manager>

Create an Account Manager with the Credential Manager

An Account Manager binds together account management functionality, of which the Credential Manager is one part. More on configuring Account Managers can be read in section Account Manager.

Account Managers are configured inside an Authentication-profile.

Example configuration in /profiles/profile/*authentication-profile*/settings/authentication-service/account-managers :

Listing 50 Account Manager configuration for HTML forms authenticator using LDAP use-case
1
2
3
4
5
6
7
8
    <account-manager>
          <id>LdapAccountManager</id>
          <credential-manager>LdapCredentialManager</credential-manager>
          <account-data-source>LdapUserstore</account-data-source>
          <enable-registration>
                <account-verification-method>no-verification</account-verification-method>
          </enable-registration>
    </account-manager>

Create the HTML Form authenticator, that uses the Account Manager

Now it’s time to configure the HTML Form authenticator. There is nothing special LDAP, apart from pointing the authenticator’s Account Manager to the right one. More in the section HTML Forms Authenticator.

Example configuration in /profiles/profile/*authentication-profile*/settings/authentication-service/authenticators :

Listing 51 HTML Forms authenticator configuration for HTML forms authenticator using LDAP use-case
1
2
3
4
5
6
7
    <authenticator>
          <id>htmlLdap</id>
          <description>A standard LDAP backed authenticator</description>
          <html-form xmlns="https://curity.se/ns/conf/authenticators/html-form">
                <account-manager>LdapAccountManager</account-manager>
          </html-form>
    </authenticator>

Enable the authenticator for Service Providers (or Clients)

Only when an authenticator is configured for a Service Provider (or Client), it will be made available. More on configuring Service Providers in the section Service Providers.

Example configuration in /profiles/profile/*authentication-profile*/settings/authentication-service/service-providers :

Listing 52 Service Provider configuration for HTML forms authenticator using LDAP use-case
1
2
3
4
5
6
7
    <service-provider>
          <id>se.curity.app</id>
          <allowed-authenticators>htmlLdap</allowed-authenticators>
          <context-info>Log into se.curity.app</context-info>
          <target-url>https://se.curity-app.com/cb</target-url>
          <template-area>html-only</template-area>
    </service-provider>

Connection Pool

As mentioned above, an LDAP data source has a pool of connections that are reused. Generally, the pool is optimized for high-throughput and low resource consumption. Changes from the default settings are not recommended for typical use cases. When changes are made, however, it is important to understand the details of how the pool works.

First, it is important to understand that the pool is divided into three groupings (as shown in Fig. 22):

  1. Idle connections
  2. Active connections
  3. Checked out connections
../../_images/parts_of_connection_pool.png

Fig. 22 Parts of the LDAP connection pool

Idle connections are those that have been created but are not currently in use. Checked out connection are those that are currently being used (i.e., have been borrowed from the pool to perform some LDAP operation). The number of active connections is the sum of the idle and checkout connections (i.e., the total number of live connections). Idle and checked out connections can grow and (potentially) shrink.

The total active connections will not exceed the maximum allowed amount; this can be set by the max-connections setting. The idle connections may be restricted to some upper bound limit as well. This is done using the initial-connections setting. This unfortunate misnomer (that is maintained for backward compatibility’s sake) should be thought of as the preferred maximum number of idle connections. Idle connections will not be created preemptively. They will only result from creation due to a need and then added to the idle pool once that need has been met. Also, idle connections will not be closed and evicted by default, making the maximum idle setting effectively useless.

The reason for this behavior (as stated above) is that the connection pool is optimized for low resource usage and high throughput. The objects are only created when a need arises. (This degrades throughput of the first request that needs a new connection but avoids resource wastage until then.) If no need arises, no objects are ever created. Once they are though, they are not deallocated because doing so would lock the connections while their activity status is checked. This locked would introduce contention that would degrade throughput. Furthermore, if they were destroyed, then they would later have to be recreated, which would be wasteful. This and the contention issue will both affect the throughput, so it is deemed better to keep the objects once they are created even if they are not in use.

Tip

When the LDAP server is configured to terminate idle connections and eviction is disabled (the default), it is very important to enable validate-connections. Otherwise, an idle connection may be picked up out of the pool which the server has killed. When this setting is true, the connection’s liveliness will be verified when it is borrowed from the pool. This will reactively verify that a connection that has been sitting idle for a long period of time is still functional prior to any usage. This liveliness check will take time, and it and idleness checks on the LDAP server should be disabled in a spiky system with sufficient memory.

If this default behavior is not preferred, for example, because the system usage is spiking and the connections are consuming too much memory (in the Curity Identity Server and/or the LDAP server) during the lows, an evictor can be configured to run. This scavenger will evict idle connections that have not been used for some amount of time. This amount can be set using the time-between-eviction-runs setting. This will cause the evictor to run periodically. When it does, it will check at most three connections to see if they are idle and should be deallocated. During the next cycle, another three will be checked and so on. This low number of object idle checks is done to avoid protracted locking of live connections.

The pool is implemented as a last-in-first-out data structure. In this way, it functions like a stack. As a result, the last used connection in the pool will be the first to be reused. As a result, unused connections will be pushed back further and further in the line of to-be-used objects. This will ensure that there are more opportunities to scavenge unused connections if an evictor is configured to run.

If the active connection count is reached, requests for an object from the pool will block. Eventually, this wait will timeout or a connection will be obtained. The timeout is not currently configurable. Additional unconfigurable settings exist on the pool. These can be observed with JMX (when enabled), but are intentionally undocumented and subject to change.

When JMX is enabled, the pool and its various settings can be viewed in an MBean Browser (like Zulu Mission Control) by accessing the GenericObjectPool setting within the org.apache.commons.pool2 folder. From there, each LDAP data source that has at least one active connection will be listed. When accessed, all settings will be shown. The meaning of these do not directly correspond to the settings defined in the the Curity Identity Server data model and their interpretation is intentionally not provided. Inclusion of this information is only intended to aid in difficult troubleshooting scenarios.