= LDAP synchronizer
:description: Learn how to configure the LDAP Synchronizer. This tool updates Bonita Users and Groups database from the LDAP directory.

Learn how to configure the LDAP Synchronizer. This tool updates Bonita Users and Groups database from the LDAP directory.

[NOTE]
====
For Subscription editions only.
====

The LDAP synchronization service keeps the Bonita organization information synchronized with an external LDAP directory, by creating, updating, or removing
users and groups in the organization
to match as closely as possible the user list attributes defined in LDAP. It does not modify the LDAP directory.

The LDAP Synchronizer connects to both the LDAP server and Bonita Engine to read the data from the LDAP server and modify the organization in the Bonita Engine database using the API.
Both the Engine and the LDAP server must be running when the LDAP Synchronizer tool is run.

The synchronizer program runs in the background. There is no user interface: all configuration settings are specified in files and
all output is written to a log file.

== LDAP objects supported

The synchronizer will synchronize LDAP objects that inherit from the "person" class as users in Bonita.
The synchronizer application does not support user meta data and cannot synchronize passwords. A new user password is initialized with the user name.

The tool supports LDAP groups of the following classes (all of the verifications are case-insensitive) :

* group
* groupOfURLs
* groupOfNames
* groupOfUniqueNames
* ds-virtual-static-group

== What does the LDAP synchronizer do

Below are all the actions completed by the LDAP synchronizer tool:

. Reads all Users in the source LDAP directory
. Creates all Users in the bonita engine db
. Reads all Groups in the source LDAP directory
. Creates all Groups in the Bonita Engine db
. Retrieves all Users that are belonging to the groups in the source LDAP directory
. Retrieves all Users that are belonging to the groups in the Bonita Engine db
. For all Users belonging to the groups in the Bonita Engine db and not in the groups in the source LDAP directory, do Delete membership (user, role-in-ldap-tool-config, group)
. Creates all memberships for all users and groups with a configured role (user, role-in-ldap-tool-config, group)

To run the LDAP synchronizer, execute the script `BonitaSubscription-x.y.z-LDAP-Synchronizer.bat` (for Windows) or `BonitaSubscription-x.y.z-LDAP-Synchronizer.sh` (for Linux),
where `x.y.z` is the version of Bonita you are running.

WARNING: Do not modify the Organization from the Bonita Portal while the tool is running, as this will cause a synchronization error.

NOTE: Some use cases require additional configuration server side (for example to use directly the engine API). They are described xref:configure-client-of-bonita-bpm-engine.adoc[here].


== Using the LDAP synchronizer Docker image

How to install and use the LDAP Synchronizer docker distribution.

This guide assumes you have a working docker environment.

=== Configuration

==== Environment Variables

All general connection settings( `bonita.properties`, `ldap.properties`
and `log.properties`) are configurable with environment properties.

Specific configuration available on `mapper.properties` and `sync.properties` could configurable with a copy of files in directory link by volume `/opt/conf/user-config`.

Those files could be copied directly from ldap-syncrhonizer docker image with command to directory link to volume `/opt/conf/user-config` with  :

[source,bash,subs="verbatim,quotes"]
----
docker cp $(docker create --rm quay.io/bonitasoft/bonita-ldap-synchronizer:*version*):/conf/default/*conFileName*.properties *directory_link_to_volume*
----

*e.g* : Overwrite the  `sync.properties` file
* create directory link to the volume
----
mkdir user-config
----
* copy the file from the base image using the command :
----
docker cp $(docker create --rm quay.io/bonitasoft/bonita-ldap-synchronizer:*version*):/conf/default/sync.properties ./user-config/
----
* edit the file
* start the docker image with the volume docker run [...] -v $(pwd)/user-config:/opt/conf/user-config [..]


xref:ldap-synchronizer.adoc#ldap-configuration-files[here] more details about configuration files.

*WARN:* `bonita.properties`, `ldap.properties` and `log.properties`  files located on volume will overwrite all configuration specified with environment variables.

===== Bonita connection settings

[width="100%",cols="34%,33%,33%",options="header",]
|===
|Name |Default |Description
|`BONITA_URL` |http://localhost:8080 |Url to connect to the server
|`BONITA_APP_NAME` |bonita |Application name
|`BONITA_LOGIN` |install |Username of the Bonita account used for
synchronization.
|`BONITA_PASSWORD` |install |Password of the Bonita account used for
synchronization.
|`BONITA_PLATFORM_LOGIN` |platformAdmin |This is the username of the
platform administrator.
|`BONITA_PLATFORM_PASSWORD` |platform |This is the password of the
platform administrator.
|===

=====  Ldap connection settings

[width="100%",cols="34%,33%,33%",options="header",]
|===
|Name |Default |Description
|`LDAP_HOST_URL` |ldap://localhost:389/ |Host name and port of the LDAP
server.
|`LDAP_AUTH_TYPE` |simple |LDAP authentication type (supported values:
none, simple or strong)
|`LDAP_PRINCIPAL_DN` |cn=Directory Manager |distinguished name (DN) of
the user account used for browsing through the LDAP users
|`LDAP_PRINCIPAL_PASSWORD` |root |password of the LDAP browser account
|`LDAP_ENFORCE_SSL` |false |force the connection between ldap client and
server to use ssl
|`LDAP_DIRECTORY_USER_TYPE` |person |type of the user object (``user''
for an Active Directory, ``person'' for an LDAP)
|`LDAP_USE_PAGE_SEARCH` |false |*Not supported by all LDAP servers* :
Paged search to true to activate page pagination
|`LDAP_PAGE_SIZE` |1000 |Number page result by search query
|===

=====  LOGGER CONFIGURATION

[width="100%",cols="34%,33%,33%",options="header",]
|===
|Name |Default |Description
|`LOG_DATE_PREFIX` |yyyy-MM-dd |date format used for prefixing the log
file name ( see
https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/text/SimpleDateFormat.html[SimpleDateFormat]
|`LOG_LEVEL` |INFO |level of reporting of the logger (relevant values
are INFO for production use, FINE for debug use)
|===

=== Run
[source,bash,subs="verbatim,quotes"]
----
docker run -v *CONF-DIR-PATH*:/opt/conf/user-config quay.io/bonitasoft/bonita-ldap-synchronizer
----

* *CONF-DIR-PATH* could contain all properties

*eg :*
[source,bash]
----
docker run  -e BONITA_URL=http://192.168.0.10:8080 -v $(pwd)/bonita-ldap-synchronizer/conf:/opt/conf/user-config  quay.io/bonitasoft/bonita-ldap-synchronizer
----

==== LOG

All logs are produce on console output.

== Using the LDAP synchronizer from the Bonita bundle

To install the synchronizer, unzip the Tomcat bundle and configure the files located under the tools/BonitaSubscriptionLDAPSynchronizer/conf directory.
This directory contains a sample configuration in the `conf/default` subfolder which is used to perform LDAP synchronization
on the default tenant. This is also possible to perform the synchronization on a <<non-default-tenant,non default tentant>>
which requires dedicated configuration.

Two way to connect the Bonita Engine is possible:

1/ Connection using the Environment variables:

Set the HTTP connection parameters used by the LDAP Synchronizer, by editing the `<LDAP_SYNCHRONIZER>\BonitaSubscription-<version>-LDAP-Synchronizer.(bat or sh)` file.

Add between `java` and `-classpath`:

[source,bash]
----
-Dorg.bonitasoft.engine.api-type.server.url=http://localhost:8080 -Dorg.bonitasoft.engine.api-type.application.name=bonita
----

The LDAP Synchronizer connects to Bonita server using the HTTP mode only.
For more understanding about API access, see the xref:engine-api-overview.adoc[Engine API overview].

2/ Connection using Bonita.properties files:

See bonita.properties section

Customize the configuration for your system, by editing the configuration files.
There are some additional considerations for using the LDAP synchronizer in a non-default tenant.


[[ldap-configuration-files]]
== Configuration files

There are five properties files:

* bonita.properties defines the Bonita connection settings and specifies the account used for user synchronization (requires administration privileges).
* ldap.properties defines the LDAP connection settings and specifies the account used for user browsing.
* logger.properties provides the settings for the logger. Default settings should be fine for most uses.
* mapper.properties specifies the translation between Bonita and LDAP directory user attributes.
* sync.properties defines the synchronization settings.

All configurations files can be found in the conf directory.

NOTE: to use a special character in a properties file, use the Unicode equivalent. For example, for `à` use \u00E0.
You can use a tool such as http://docs.oracle.com/javase/8/docs/technotes/tools/unix/native2ascii.html[native2ascii] to convert any special characters in the configuration files to Unicode.

You also need to xref:configure-client-of-bonita-bpm-engine.adoc[configure connection on Bonita Engine] for the LDAP Synchronizer.

=== bonita.properties

This file defines the connection settings and specifies the account used for user synchronization (requires administration privileges).

|===
| Item | Description | Default

| bonita_home
| The path to the Bonita Home folder of the LDAP Synchronizer. (deprecated)
|

| serverUrl
| Url to access the Bonita Server (http://myHost:8080)
| no default value

| applicationName
| Application name (bonita is the general name)
| no default value

| login
| The login to provide is a userName.
| install

| password
| Password of the Bonita account used for synchronization.
| install

| technicalUser
| This is the xref:first-steps-after-setup.adoc[username of the platform adminstrator].
| platformAdmin

| technicalPassword
| This is the xref:first-steps-after-setup.adoc[password of the platform adminstrator].
| platform
|===

=== ldap.properties

This file defines the LDAP connection settings and specifies the account used for user browsing.

|===
| Item | Description | Default

| host_url
| LDAP server URL
| ldap://localhost:389

| auth_type
| LDAP authentication type (supported values: none, simple or strong)
| simple

| principal_dn
| distinguished name (DN) of the user account used for browsing through the LDAP users
| cn=Directory Manager

| principal_password
| password of the LDAP
| root

| directory_user_type
| type of the user object ("user" for an Active Directory, "person" for an LDAP)
| person

| use_paged_search
| activate search pagination (Not supported by all LDAP servers)
| false

| page_size
| number of results in ldap search pages (Not supported by all LDAP servers)
| 1000

| enforce_ssl
| force the connection between ldap client and server to use ssl
| false

| truststore_path
| allow to configure the java truststore path,  in case of you want to use different keystore than the default
|

| truststore_password
| allow to configure the java truststore password, in case of you want to use a different keystore password than the default
|

| truststore_type
| type of the trust store (if different than JKS)
|

| disable_endpoint_authentication
| can be useful when using a self-signed certificate
| false
|===

=== logger.properties

This file provides the settings for the logger. Default settings should be fine for most uses.

|===
| Item | Description | Default

| log_dir_path
| directory path where the log files will be stored. The log files are named on the following template: _`log_file_date_prefix`_`_LDAP-BOS_Synchronizer.log`
| logs/

| log_file_date_prefix
| date format used for prefixing the log file name
| yyyy=MM=dd

| log_level
| level of reporting of the logger (relevant values are INFO for production use, FINE for debug use)
| INFO
|===

The date format in log file names follows the syntax of the Java SimpleDateFormat class.
This is useful to control the number of log file create as the logger will append information to an existing log file if the file name already exists.
Example: if you set the format to "?yyyy-mm", you will get one new log file per month.

=== mapper.properties

This file specifies the translation between Bonita and LDAP directory user attributes such as:
`bonita_property = ldap_property`

The only mandatory property is user_name, which is the key defined for matching users. All other properties are optional.

An LDAP property may be used several times in the configuration file but each Bonita property should be defined only once. Unused properties should be commented out.

These are the supported Bonita user properties:

|===
| General information | Professional information | Personal information | Custom User Information

| user_name  +
first_name  +
last_name  +
title  +
job_title  +
manager
| pro_email  +
pro_phone  +
pro_mobile  +
pro_fax  +
pro_website  +
pro_room  +
pro_building  +
pro_address  +
pro_city  +
pro_zip_code  +
pro_state  +
pro_country
| perso_email  +
perso_phone  +
perso_mobile  +
perso_fax  +
perso_website  +
perso_room  +
perso_building  +
perso_address  +
perso_city  +
perso_zip_code  +
perso_state  +
perso_country
| custom_\<Custom User Information>
|===

The following items are configured by default:

|===
| Item | Default
| user_name| uid
| last_name| sn
| title| title
| pro_email| mail
| pro_phone| telephoneNumber
| pro_mobile| mobile
| perso_phone| homePhone
|===

*Custom User Information*

The prefix ''custom_'' is used to map any 'Custom User Information'. For example, to map the 'Custom User Information' "skypeId" and "room"
from LDAP property "skype" and "roomNumber", the syntax is:

[source,properties]
----
custom_skypeId = skype
custom_room = roomNumber
----

=== sync.properties

This file defines the synchronization settings.

* error_level_upon_failing_to_get_related_user: optional parameter that specifies whether an error should be blocking upon getting related users (manager) +
Supported values: ignore, warn or fatal +
Default value: warn
* bonita_username_case: optional parameter that specifies whether the LDAP user names should be converted to a given case upon being imported in Bonita. +
Supported values: mixed, uppercase or lowercase +
Default value: lowercase
* ldap_watched_directories: defines the LDAP directories to watch. +
Supported values: list of LDAP watched directory object identifiers separated by commas. +
The syntax for watched directory object properties is detailed in the next section.
* bonita_nosync_users: specifies the list of users who should not be synchronized. +
Supported values: user names separated by commas.
* bonita_user_role: specifies the role assigned to Bonita users. +
Default value: user
* bonita_deactivate_users: optional parameter that specifies whether the tool should deactivate Bonita users who are not present in LDAP.
When bonita_deactivate_users is set to true, a Bonita user who is not present in LDAP is deactivated. The user are not removed from Bonita, but they cannot start process instances or do tasks.
* bonita_reactivate_users: optional parameter that specifies whether the tool should reactivate Bonita users who are deactivated in bonita but present in LDAP. +
Supported values: true or false +
Default value: true
* allow_recursive_groups: optional parameter that specifies whether sub-groups should also be synchronized. The operation does not preserve the group hierarchy however, and the LDAP sub-groups will be created at root level in Bonita organization. +
Supported values: true or false +
Default value: true
* ldap_groups: optional parameter that specifies the LDAP groups that should be synchronized. +
Supported values: list of LDAP Group object identifiers separated by commas. +
The syntax for group object properties is detailed in a later section.
* bonita_user_custominfo_policy: Define the policy to synchronize the 'Custom User Information'. The
different policy is detailed in a later section. +
Default value: none
* allow_custominfo_creation: define the strategy when a Custom User Information is detected
  in the mapper.properties configuration, and not exist in the Bonita database. If this
  property is true, then the Custom User Information is created. +
Default value: false

=== Policy to synchronize the Custom User Information

In Bonita, you can defined a set of Custom User Information attributes. Then, each user has
a value for each attribute.
A policy named  bonita_user_custominfo_policy gives the strategy to synchronize this
information.
All examples are based on

. Two Custom User Information exist in the Bonita database : _badgeId_ and _room_
. The mapper.properties contains

[source,properties]
----
custom_badgeId = ldapBadgeIdentification
----

The _room_ is not declared in the mapper.properties.

* *none*:

[source,properties]
----
bonita_user_custominfo_policy = none
----

no 'Custom User Information' is synchronized.

* *partial* :

[source,properties]
----
bonita_user_custominfo_policy = partial
----

Synchronize only 'Custom User Information' declared in the mapper.properties.

A 'Custom User Information' not declared in mapper.properties will not be modified. When the Ldap Object doesn't have a property, it will not be modified.

|===
| LDAP object | LDAP property | Synchronization
| WalterBates| _ldapBadgeIdentification_== 'walterSid'| (Synchronized) _badgeId_=='walterSid'
| HelenKelly| no property _ldapBadgeIdentification_ defined| (No synchronization)
|===

* *scope*:

[source,properties]
----
bonita_user_custominfo_policy = scope
----

Same as partial, plus if the Ldap Object doesn't have a property, it will be set to null
  (all the scope is synchronized)

|===
| LDAP object | LDAP property | Synchronization
| WalterBates| _ldapBadgeIdentification_== 'walterSid'| (Synchronized) _badgeId_=='walterSid'
| HelenKelly| no property _ldapBadgeIdentification_ defined| (Set to null) _badgeId_==null
|===

* *full*:

[source,properties]
----
bonita_user_custominfo_policy = full
----

Synchronize all 'Custom User Information'. If a 'Custom User Information' is not declared in mapper.properties, or the Ldap doesn't have the property, it is set to null

|===
| LDAP object | LDAP property | Synchronization
| WalterBates| _ldapBadgeIdentification_== 'walterSid' | (Synchronized) _badgeId_=='walterSid' +_room_==null
| null||
|===

=== LDAP Watched directory object properties syntax

A watched directory is defined by an id that is declared in the "ldap_watched_directories"
list.
This id provides access to the object properties with this syntax: object_id.property.

Here are the available object properties:

|===
| ldap_search_dn| DN of the LDAP watched directory that will be used to get the list of the LDAP users.
| ldap_search_filter| LDAP user search filter (mandatory attribute, but can be a wide filter such as "cn=*").
|===

Example of a watched directory declaration:

[source,properties]
----
# Declare a list of LDAP watched directories
ldap_watched_directories = dir1,dir2

# Specify dir1 settings
dir1.ldap_search_dn =   ou=People,dc=example,dc=com
dir1.ldap_search_filter =   cn=*

# Specify dir2 settings
dir2.ldap_search_dn =   ou=OtherPeople,dc=example,dc=com
dir2.ldap_search_filter =   cn=*
----

=== LDAP Group object properties syntax

The tool will automatically detect the group class from LDAP. Here are the LDAP group classes supported by the LDAP
Synchronizer:

* group
* groupOfURLs
* groupOfNames
* groupOfUniqueNames
* ds-virtual-static-group

The tool can determine the list of users belonging to a group by looking these properties, depending on the group's objectClass:

* member: group `objectclass`
* memberURL: `groupOfURLs` objectclass
* member: `groupOfNames` objectclass
* uniqueMember: `groupOfUniqueNames` objectclass
* ds-target-group-dn: `ds-virtual-static-group` objectclass

There are two ways (they can be configured individually or at the same time) to synchronize groups

* declare a list of groups
* perform a LDAP searches to find the list of groups to synchronize

=== Synchronize a list of groups

An LDAP group is defined by an id which is declared in the "ldap_groups" list. This id provides access to the object properties with this syntax: object_id.property.
You can also specify groups with a search: all groups that match the search are synchronized.

Groups will be synchronized based on the matching of their LDAP common name (CN) and their Bonita names.

Groups can be declared individually in the configuration file with the following properties :

|===
| ldap_group_dn| mandatory attribute that specifies the DN of the LDAP group.
| forced_bonita_group_name| optional attribute that renames the Bonita group instead of using the original LDAP group name.
| force_add_non_existing_users| optional Boolean attribute (true by default) that defines whether group members (users in LDAP) that are not present in Bonita should be imported (created in Bonita). If false, these users are not created but group is created and existing users get associated with the group.
|===

Example of group declarations:

[source,properties]
----
# List of groups to synchronize
ldap_groups = group1, group2

# Specify group1 settings
group1.ldap_group_dn  =  cn=group1,ou=groups,dc=bonita,dc=com
group1.forced_bonita_group_name  =  forced group1

# Specify group2 settings:
# sync the group with specified dn but not the users inside this group
group2.ldap_group_dn  =  cn=group2,ou=groups,dc=bonita,dc=com
group2.force_add_non_existing_users  =  false
----

=== Synchronize a list of groups retrieved using a LDAP search

In combination or as an alternative, groups can be declared using the result of an LDAP search that is defined in the configuration file with the following properties :

|===
| ldap_group_search_dn| DN of the LDAP watched directory that will be used to get the list of the LDAP groups.                                                                                 |
| ldap_group_search_filter| LDAP group search filter (mandatory attribute, but can be a wide filter such as "cn=*").                                                                              |
| force_add_non_existing_users | optional Boolean attribute (true by default) that defines whether group members (users in LDAP) that are not present in Bonita should be imported (created in Bonita). If false, these users are not created but group is created and existing users get associated with the group. |
|===

Example of group searches:

[source,properties]
----
#Specify search of groups
ldap_search_filter_groups  =  search1,search2

# Specify search1 settings:
# sync all groups under ou=people,dc=bonita,dc=com with cn starting with "A_"
search1.ldap_group_search_dn  =  ou=people,dc=bonita,dc=com
search1.ldap_group_search_filter  =  cn=A_*

# Specify search2 settings:
# sync all groups under ou=people,dc=bonita,dc=com with cn starting with "B_"
# but without importing new users inside these groups
search2.ldap_group_search_dn  =  ou=people,dc=bonita,dc=com
search2.ldap_group_search_filter  =  cn=B_*
search2.force_add_non_existing_users  =  false
----


[#non-default-tenant]
== Using the LDAP synchronizer in a non-default tenant

*Installation:* The LDAP Synchronizer is installed on the platform as described above.
After installation, Check that the  xref:profiles-overview.adoc["User" profile] is defined for the tenant.
The default tenant has a "User" profile by default, but it must be created manually when a tenant is created.
The LDAP synchronizer will fail if this profile is not defined.

*Configuration:* To configure the LDAP Synchronizer for a tenant that is not the default tenant:

* Create a new folder in `$BonitaSynchronizerFolder/conf` with the same name as the name of the tenant (not the id) that was set when the tenant was created.
* Copy the contents of the default folder from `$BonitaSynchronizerFolder/conf` to this new tenant-specific folder.
* Configure the LDAP synchronizer for the tenant by editing the configuration files in the tenant-specific folder, as described above.

*Running:* To run the LDAP Synchronizer on a tenant, give the name of the tenant as a parameter of the script.

== LDAPS(TLS) Activation

*Required* LDAP server should be configured with a valid certificate signed by Certification Authority or with the Auto signed certificate.

*Configuration:* To configure the LDAP synchronizer for using encrypted connection ( TLS ) :

* Configure the LDAP synchronizer  by editing `ldap.properties` configuration file, as described above
 ** host_url= ldaps://`ldapServerHostname:ldapsServerPort` ( most common `ldapsServerPort` is 636  )
 ** enforce_ssl = `true`  +
   By default, the LDAP synchronizer uses the `default java trust Store`, but it is possible to use a custom one, by configuring the properties :
 ** truststore_path= `locationOfCustomTruststore`
 ** truststore_password= `passwordOfCustomTruststore`
 ** truststore_type= `customTruststoreType` ( default JKS)

In the following cases:

* when the server certificate is auto-signed (use of custom root certification) you might configure :
 ** the `public certificate` should be imported into the default java or custom trust Store.
 ** the endpoint authentication might be disabled `disable_endpoint_authentication=true`

== image:images/troubleshooting.png[troubleshooting-icon] Troubleshooting
=== HttpResponseException: status code: 404 is generated when the LDAP Synchronizer is used

*Symptom:* The following stacktrace appears in the log:
[source,log]
----
Aug 12, 2021 9:01:35 AM com.bonitasoft.ldapsynchronizer.repository.BonitaUserRepository initialize
INFO: Connecting to Bonita server using HTTP mode
Aug 12, 2021 9:01:38 AM com.bonitasoft.ldapsynchronizer.LDAPSynchronizer run
SEVERE: Synchronization failed
java.lang.Exception: Failed to connect to Bonita server: HTTP: url[https://localhost:8080] application[bonita] login[install] password[install]
	at com.bonitasoft.ldapsynchronizer.repository.BonitaUserRepository.initialize(BonitaUserRepository.java:177)
	at com.bonitasoft.ldapsynchronizer.repository.BonitaUserRepository.<init>(BonitaUserRepository.java:105)
	at com.bonitasoft.ldapsynchronizer.LDAPSynchronizer.run(LDAPSynchronizer.java:64)
	at com.bonitasoft.ldapsynchronizer.LDAPSynchronizer.main(LDAPSynchronizer.java:237)
Caused by: java.lang.reflect.UndeclaredThrowableException
	at com.sun.proxy.$Proxy0.login(Unknown Source)
	at com.bonitasoft.ldapsynchronizer.repository.BonitaUserRepository.initialize(BonitaUserRepository.java:157)
	... 3 more
Caused by: java.io.IOException: Error while executing POST request (http code: 404) <POST https://localhost:8080/bonita/serverAPI/org.bonitasoft.engine.api.PlatformLoginAPI/login HTTP/1.1>
	at org.bonitasoft.engine.api.HTTPServerAPI.invokeMethod(HTTPServerAPI.java:144)
	at org.bonitasoft.engine.api.impl.ClienInterceptor.invoke(ClientInterceptor.java:79)
	at com.sun.proxy.$Proxy0.login(Unknown Source)
	at com.bonitasoft.ldapsynchronizer.repository.BonitaUserRepository.initialize(BonitaUserRepository.java:157)
	at com.bonitasoft.ldapsynchronizer.repository.BonitaUserRepository.<init>(BonitaUserRepository.java:105)
	at com.bonitasoft.ldapsynchronizer.LDAPSynchronizer.run(LDAPSynchronizer.java:64)
	at com.bonitasoft.ldapsynchronizer.LDAPSynchronizer.main(LDAPSynchronizer.java:237)
	at 	< ========== Beginning of the server stack trace ========== >. ( )
	at org.bonitasoft.engine.api.HTTPServerAPI.executeHttpPost(HTTPServerAPI.java:177)
	at org.bonitasoft.engine.api.HTTPServerAPI.invokeMethod(HTTPServerAPI.java:139)
	at org.bonitasoft.engine.api.impl.ClientInterceptor.invoke(ClientInterceptor.java:79)
	... 5 more
Caused by: org.apache.http.client.HttpResponseException: status code: 404
	at org.apache.http.impl.client.AbstractResponseHandler.handleResponse(AbstractResponseHandler.java:70)
	at org.apache.http.impl.client.BasicResponseHandler.handleResponse(BasicResponseHandler.java:66)
	at org.apache.http.impl.client.BasicResponseHandler.handleResponse(BasicResponseHandler.java:52)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:223)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:165)
	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:140)
	at org.bonitasoft.engine.api.HTTPServerAPI.executeHttpPost(HTTPServerAPI.java:169)
	... 7 more
----

*Root cause:*
The LDAP Synchronizer is using the Engine HTTP API of the product but it's not active in your configuration.

*Solutions:*

*On-premise solution*: Configure the ZIP bundle you've downloaded from the bonitasoft Customer Service Center
* Edit the `/server/webapps/bonita/WEB-INF/web.xml` file and make sure these lines are not commented:
[source,xml]
----
 <servlet>
        <servlet-name>HttpAPIServlet</servlet-name>
        <servlet-class>org.bonitasoft.engine.api.internal.servlet.HttpAPIServlet</servlet-class>
 </servlet>
----
*Docker image solution:* Run the docker image with *-e HTTP_API=true*
* For example: `docker run -e HTTP_API=true -e REST_API_DYN_AUTH_CHECKS=false --name bonita -v ./bonita-lic/:/opt/bonita_lic/ -h localhost -d -p 8080:8080 quay.io/bonitasoft/bonita-subscription:7.9.2`
* See the page xref:bonita-docker-installation.adoc#_http_api[Deploy Bonita Runtime with Docker] for more information.
