Skip to content

Synchronize data with Active Directory via LDAP ​

This guide demonstrates how to use Deskradar LDAP companion application to sync your LDAP data to your Deskradar instance.

Deskradar LDAP companion is a CLI application provided as a Docker container. It connects to your LDAP endpoint, downloads the data and pushes it to your Deskradar instance. On Deskradar, it initiates import process by creating an import job.

NOTE

The application can be run on demand manually or launched by a task scheduling mechanism of your choice.

IMPORTANT

If an import that used to work now fails with Request failed with status code 405, you are running version 1.2.1. One parameter change restores it: see Resolve "Request failed with status code 405". To move to version 2, which authenticates with an API key instead of a Deskradar user email and password, see Upgrade from version 1.2.1.

Prerequisites ​

  1. LDAP is enabled on your domain controller
  2. Worker node to run the application
    1. Docker is installed on the worker node
    2. Worker node can access your LDAP server
    3. Worker node can reach your Deskradar instance
  3. A Deskradar API key with the role Editor or Administrator. See Create an API key.

Create an API key ​

The companion signs in to Deskradar with an API key. You need the Administrator role to create one.

  1. In the sidebar, select Team, then open the API Keys tab.
  2. Select New API key.
  3. Enter a name that identifies the purpose of the key, such as LDAP companion.
  4. Set Role to Editor. The form preselects Viewer, and a key with that role cannot start an import.
  5. Set Expires. The form preselects 30 days. A scheduled import stops working on the day its key expires, so select Never for an unattended import, or choose a date and plan to replace the key before then.
  6. Select Create, then copy the key and store it somewhere safe. Deskradar shows the key only once.

Install on Linux worker node ​

Pull the image from the GitHub Container Registry. The package is public, so you do not need an account or a login.

bash
docker pull ghcr.io/deskradar/ldap-companion:2

Every release publishes four tags. Pin 2 to receive compatible updates automatically, or pin an exact version such as 2.0.1 if you prefer to control when the companion changes.

TagWhat it points to
2the newest version 2 release
2.0the newest 2.0.x release
2.0.1that exact build, forever
latestthe newest release of any version

If your worker node cannot reach the internet, pull the image on a machine that can, then transfer it:

bash
docker save ghcr.io/deskradar/ldap-companion:2 | gzip > ldap-companion.tar.gz
# copy the file to the worker node, then:
gzip -dc ldap-companion.tar.gz | docker load

Running the application ​

bash
docker run ghcr.io/deskradar/ldap-companion:2 <command> <options>

Run without parameters to get help:

bash
docker run --rm ghcr.io/deskradar/ldap-companion:2
bash
docker run --rm ghcr.io/deskradar/ldap-companion:2 help
bash
docker run --rm ghcr.io/deskradar/ldap-companion:2 <command> --help

File permissions ​

The container runs as an unprivileged user rather than as root. The export command writes its output to a directory you mount, so that directory has to be writable by that user. The simplest way to guarantee this is to run the container as yourself:

bash
docker run --rm -v $(pwd)/data:/data --user "$(id -u):$(id -g)" \
ghcr.io/deskradar/ldap-companion:2 export --output /data/output.csv

The push ldap command sends data straight from your LDAP server to Deskradar without writing anything to disk, so it needs no mounted directory and no extra permissions.

Upgrade from version 1.2.1 ​

Version 2 changes how the companion proves who it is. Instead of a Deskradar user email and password, it uses an API key. This is the only change to your parameters.

Your LDAP parameters, your JSON configuration file, your data processing middleware and your scheduler entry all continue to work unchanged.

Step 1: create an API key ​

Follow Create an API key and give the key the Editor role. Check the Expires setting before you create the key, because an expired key stops your scheduled import.

Step 2: change the credentials ​

Replace the two credential parameters with the key:

RemoveAdd
--site-email, --site-password--api-key
CONF_SITE_EMAIL, CONF_SITE_PASSWORDCONF_API_KEY
siteEmail, sitePasswordapiKey

Step 3: remove the compatibility prefix ​

If you added /api/v1/legacy to --site-uri to work around the Request failed with status code 405 error, remove it. Version 2 calls the current addresses, so --site-uri takes your instance root again:

text
--site-uri "https://acme.deskradar.cloud"

Step 4: pull the new image ​

bash
docker pull ghcr.io/deskradar/ldap-companion:2

Your command changes from this:

bash
docker run --rm -v $(pwd)/data:/data \
deskradar_ldap-companion:latest push csv \
--site-uri "https://acme.deskradar.cloud/api/v1/legacy" \
--site-email "automation-editor@acme.com" \
--site-password "p4Ssw0r6" \
--file /data/input.csv \
--columns "displayName,email,buildingName,floorLabel" \
--resource staff

to this:

bash
docker run --rm -v $(pwd)/data:/data \
ghcr.io/deskradar/ldap-companion:2 push csv \
--site-uri "https://acme.deskradar.cloud" \
--api-key "dr_v1_..." \
--file /data/input.csv \
--columns "displayName,email,buildingName,floorLabel" \
--resource staff

Step 5: confirm the import ​

Run the new command once by hand before you return it to your scheduler. A successful run logs Import job created with the job identifier, and ends with Data push completed. If the run stops instead, the message names the cause:

MessageCauseWhat to do
the API key is missing, invalid or revokedThe key is mistyped, expired or deleted.Create a new key and update your configuration.
the API key needs the "editor" or "admin" roleThe key has the Viewer role.Create a key with the Editor role.
no endpoint at ... Check that --site-uri points at the instance root--site-uri still ends with /api/v1/legacy.Remove the suffix, as described in step 3.
EACCES: permission deniedA file that you mount is readable only by its owner. Version 1.2.1 ran as root inside the container and version 2 does not.Add --user "$(id -u):$(id -g)" to the command, as File permissions shows.

If you created a Deskradar user only for the companion, the companion no longer signs in with it, and an administrator can remove that user.

Resolve "Request failed with status code 405" ​

If you are not ready to upgrade, version 1.2.1 still works. A Deskradar update moved the addresses that the API serves, so a 1.2.1 companion reports Request failed with status code 405 at its first request. Status code 405 means "Method Not Allowed": the request reached Deskradar, but the address it went to no longer accepts it. Nothing is wrong with your LDAP settings, your credentials or your CSV data, and no data was changed.

To keep 1.2.1 running, add the compatibility prefix /api/v1/legacy to the value of --site-uri:

text
--site-uri "https://acme.deskradar.cloud/api/v1/legacy"

The prefix affects only the push csv and push ldap commands, which are the ones that talk to Deskradar. The export command reads your LDAP server and writes a local file, so it never contacted the API and was never affected.

We recommend upgrading when convenient, because the compatibility prefix exists to give you time rather than as a permanent arrangement.

Commands ​

  • export command downloads the data from the LDAP server and saves it locally as a CSV or JSON file.
  • push csv command uploads the data from a local CSV file to your Deskradar instance.
  • push ldap command upload the data from your LDAP server to your Deskradar instance.

Configuration ​

The application can be configured using following options:

  1. Command line parameters
  2. Environment variables
  3. JSON configuration file

Configuration methods can be used in combination. Whereas, a single parameter can be defined using multiple configuration methods. In that case the value is determined by the configuration method with the highest priority. The order in which the configuration methods are listed above, reflects that priority.

Example. If a parameter defined in the command line, then the different value of the same parameter specified in the environment variable or JSON configuration file will be ignored.

Quick Start ​

Run application with command line parameters ​

Example for running application to export LDAP data to a CSV file on a Linux host.

shell
docker run --rm -v $(pwd)/data:/data \
ghcr.io/deskradar/ldap-companion:2 export \
--ldap-uri "ldaps://ldap.acme.lan:636" \
--ldap-username "admin" \
--ldap-password "p4Ssw0r6" \
--base-dn "cn=users,dc=acme,dc=com" \
--attributes "displayName,userPrincipalName" \
--format csv \
--output /data/output.csv

Example for pushing that file to your Deskradar instance:

shell
docker run --rm -v $(pwd)/data:/data \
ghcr.io/deskradar/ldap-companion:2 push csv \
--site-uri "https://acme.deskradar.cloud" \
--api-key "dr_v1_..." \
--file /data/output.csv \
--columns "displayName,email,buildingName,floorLabel" \
--resource staff

Every row needs a buildingName and a floorLabel, and both must already exist on your instance. A row that names a building Deskradar does not know is rejected with BUILDING_NOT_FOUND. The import job still finishes as completed in that case, so open the job and check the failed row count rather than assuming the push worked.

Example for doing both steps at once, straight from LDAP:

shell
docker run --rm \
ghcr.io/deskradar/ldap-companion:2 push ldap \
--ldap-uri "ldaps://ldap.acme.lan:636" \
--ldap-username "admin" \
--ldap-password "p4Ssw0r6" \
--base-dn "cn=users,dc=acme,dc=com" \
--attributes "displayName,userPrincipalName,physicalDeliveryOfficeName,departmentNumber" \
--site-uri "https://acme.deskradar.cloud" \
--api-key "dr_v1_..." \
--columns "displayName,email,buildingName,floorLabel" \
--resource staff

--attributes and --columns are matched by position, so the two lists must hold the same number of entries. This example reads the office and the department number from your directory and sends them as the building and the floor. Use whichever attributes your directory actually populates.

Configure application with a JSON configuration file ​

Default configuration:

json
{
  "logLevel": "info",
  "format": "json",
  "attributes": "displayName,userPrincipalName",
  "uuidAttributes": "objectGUID",
  "base64Attributes": "objectSid,thumbnailPhoto,jpegPhoto",
  "columns": "displayName,email",
  "resource": "staff",
  "attributesUpdateMode": "replace",
  "removeUnmatchedMode": "none"
}

Example JSON configuration file overriding some parameters:

json
{
  "ldapUri": "ldaps://ldap.acme.lan:636",
  "ldapUsername": "admin",
  "ldapPassword": "p4Ssw0r6",
  "baseDn": "cn=users,dc=acme,dc=com",
  "attributes": "displayName,userPrincipalName",
  "format": "csv",
  "output": "/data/output.csv"
}

To configure application with a JSON configuration file, create a config.json file. Then run the application with the local file mounted into the container on path exactly /app/config/local.json:

bash
docker run --rm \
-v $(pwd)/config.json:/app/config/local.json \
ghcr.io/deskradar/ldap-companion:2 export

Configure application with environment variables ​

bash
docker run --rm \
-v $(pwd)/data:/data \
-e LOG_LEVEL=trace \
-e CONF_LDAP_URI=ldaps://ldap.acme.lan:636 \
-e CONF_LDAP_USERNAME=admin \
-e CONF_LDAP_PASSWORD=p4Ssw0r6 \
-e CONF_BASEDN=cn=users,dc=desk,dc=radar \
-e CONF_ATTRIBUTES=displayName,userPrincipalName \
-e CONF_FORMAT=csv \
-e CONF_OUTPUT=/data/output.csv \
ghcr.io/deskradar/ldap-companion:2 export

Configuration Parameters ​

Configure logging ​

Command line argumentEnvironment variableJSON configuration file key name
--quiet or --verboseLOG_LEVELlogLevel

Valid values for environment variables and JSON configuration file: trace, debug, info, warn, error, fatal.

Use --quiet to set logLevel to warn (display only errors and warnings) or --verbose to set logLevel to debug to show more log messages.

Default: info

Commands: export, push csv, push ldap

LDAP username ​

Command line argumentEnvironment variableJSON configuration file key name
--ldap-username <string>CONF_LDAP_USERNAMEldapUsername

Username for LDAP server connection.

Default: empty

Commands: export, push csv, push ldap

LDAP password ​

Command line argumentEnvironment variableJSON configuration file key name
--ldap-password <string>CONF_LDAP_PASSWORDldapPassword

Password for LDAP server connection.

Default: empty

Commands: export, push csv, push ldap

Base DN ​

Command line argumentEnvironment variableJSON configuration file key name
--base-dn <string>CONF_BASEDNbaseDn

Base DN for the LDAP connection.

Example: cn=users,dc=acme,dc=com

Default: empty

Commands: export, push csv, push ldap

LDAP Filter ​

Command line argumentEnvironment variableJSON configuration file key name
--ldap-filter <string>CONF_LDAP_FILTERldapFilter

Search query for LDAP search.

Example: (&(physicalDeliveryOfficeName=Chicago)(department=ExampleDepartment))

Default: empty

Commands: export, push csv, push ldap

LDAP URI ​

Command line argumentEnvironment variableJSON configuration file key name
--ldap-uri <string>CONF_LDAP_URIldapUri

URL of the LDAP server.

Example: ldaps://10.0.0.24:636

Default: empty

Commands: export, push csv, push ldap

Format ​

Command line argumentEnvironment variableJSON configuration file key name
--format <string>CONF_FORMATformat

Format in which to save the exported LDAP data. Valid values: json or csv.

Default: json

Commands: export

Output ​

Command line argumentEnvironment variableJSON configuration file key name
--output <string>CONF_OUTPUToutput

Path to file to which the exported LDAP data needs to be written.

Default: empty

Example: /app/data/output.csv

Commands: export

Attributes ​

Command line argumentEnvironment variableJSON configuration file key name
--attributes <list>CONF_ATTRIBUTESattributes

Comma separated list of attributes to select from the LDAP records. Attributes list must have exactly the same number of items in the respective order as the columns list defined by the Columns parameter.

Default: displayName,userPrincipalName

Example: displayName,userPrincipalName,physicalDeliveryOfficeName,roomNumber,userWorkstations

Commands: export, push csv, push ldap

UUID attributes ​

Command line argumentEnvironment variableJSON configuration file key name
--uuid-attributes <list>CONF_UUID_ATTRIBUTESuuidAttributes

Comma separated list of LDAP attribute names which need to be converted to UUID string.

Default: objectGUID

Commands: export, push csv, push ldap

Base64 Attributes ​

Command line argumentEnvironment variableJSON configuration file key name
--base64-attributes <list>CONF_BASE64_ATTRIBUTESbase64Attributes

Comma separated list of LDAP attribute names which contain binary data and need to be encoded as Base64 string.

Default: objectSid,thumbnailPhoto,jpegPhoto

Commands: export, push csv, push ldap

Deskradar instance URL ​

Command line argumentEnvironment variableJSON configuration file key name
--site-uri <string>CONF_SITE_URIsiteUri

Your Deskradar instance base URL.

Example: https://acme.deskradar.cloud

Give the instance root. The companion appends the API path itself. If you are still running version 1.2.1 and added the /api/v1/legacy prefix here, see Upgrade from version 1.2.1.

Default: empty

Commands: push csv, push ldap

Deskradar API key ​

Command line argumentEnvironment variableJSON configuration file key name
--api-key <string>CONF_API_KEYapiKey

An API key created in Deskradar, holding the role Editor or Administrator. The key is shown only once when you create it, so store it somewhere safe.

The companion sends the key in the x-api-key header. It never opens a session and never stores a cookie.

Treat the key as a password. Prefer CONF_API_KEY or a mounted JSON configuration file over a command line argument, because command lines are visible to other users of the worker node through the process list.

Example: dr_v1_...

Default: empty

Commands: push csv, push ldap

CSV file ​

Command line argumentEnvironment variableJSON configuration file key name
--file <string>CONF_FILEfile

Path to CSV file which needs to be pushed to your Deskradar instance.

Example: /app/data/input.csv

Default: empty

Commands: push csv

Columns ​

Command line argumentEnvironment variableJSON configuration file key name
--columns <list>CONF_COLUMNScolumns

Comma separated list of column names for creating an import job on your Deskradar instance. Certain columns are required for certain resource types. Resource type is defined by the Resource parameter. Columns list must have exactly the same number of items in the respective order as the attributes list defined by the Attributes parameter.

Valid column names:

Column nameRequired for resource typesResource typesValidationsNotes
buildingNameanyanystring, max length 20 charactersBuilding names must be unique on your Deskradar instance.
floorLabelanyanystring, max length 3 charactersFloor labels must be unique within every building on your Deskradar instance.
locationIdRequired: desks, rooms, utilities. Optional: staffanystring, max length 36 characters, regex: /^[a-zA-Z0-9_\.\:\/\\-]+$/Identifies the location of the marker.
emailstaffanystring, valid emailEmail identifies staff marker and must be unique for resource type staff.
firstNameoptionalstaffstring, max length 48 charactersPerson first name
lastNameoptionalstaffstring, max length 48 charactersPerson last name
displayNameoptionalanystring, max length 100 charactersValue is used for the marker name. If not defined, firsName and lastName will be combined to construct the resulting name.
roleoptionalanystring, max length 100 charactersComma separated list of strings can used.
statusoptionalanystring, must be one of available, unavailable or remote (only for resource type staff)Marker status. Default: available.
statusTextoptionalanystring, max length 140 charactersMarker status text
nicknameoptionalstaffstring, max length 100 charactersPerson nickname
urloptionalanystring, max length 100 charactersURL of the relevant website or resource details page
skypeoptionalanystring, max length 100 charactersSkype username
twitteroptionalanystring, max length 100 charactersTwitter handle
linkedinoptionalanystring, max length 100 charactersLinkedIn profile
phoneOfficeoptionalanystring, max length 100 charactersOffice phone number
phoneMobileoptionalanystring, max length 100 charactersMobile phone number
notesoptionalanystring, max length 1000 charactersMarker notes
deskTypeoptionaldesksstring, must be one of spare, hotDefault: spare

Example: displayName,email,buildingName,floorLabel,locationId

Default: displayName,email

Commands: push csv, push ldap

Resource ​

Command line argumentEnvironment variableJSON configuration file key name
--resource <string>CONF_RESOURCEresource

Resource type for the import job on your Deskradar instance. Setting different resource type may require changes in the Columns parameter setting. See Columns parameter.

Valid values: staff, desks, rooms, utilities

Default: staff

Commands: push csv, push ldap

Attributes update mode ​

Command line argumentEnvironment variableJSON configuration file key name
--attributes-update-mode <string>CONF_ATTRIBUTES_UPDATE_MODEattributesUpdateMode

Existing marker attributes update mode for import. Set to merge to keep the attributes of the existing markers that are not imported as part of the import procedure, but defined by the editors. For more information on, please refer to the import documentation.

Valid values: replace, merge

Default: replace

Commands: push csv, push ldap

Remove unmatched marker mode ​

Command line argumentEnvironment variableJSON configuration file key name
--remove-unmatched-mode <string>CONF_REMOVE_UNMATCHED_MODEremoveUnmatchedMode

Existing marker removal mode. For more information on, please refer to the import documentation.

Valid values: none, floorScope, all

Default: none

Commands: export, push csv, push ldap

Override JSON ​

Command line argumentEnvironment variableJSON configuration file key name
--override-json <string>CONF_OVERRIDE_JSONoverrideJson

Override entry data with data from given JSON string. JSON must be an object with keys for every field you want to override in the data entry. Values in the JSON object must be strings. Fields don't have to exist in the entry.

Example: {"buildingName":"Headquarters"}

Default: empty

Commands: export, push csv, push ldap

Data Processing Middleware ​

In order to modify or filter the data delivered by the LDAP endpoint before exporting it to CSV file or pushing it to Deskradar, use data processing middleware.

Data processing middleware is a JavaScript function that receives a single argument (an array of objects containing the data obtained from the LDAP endpoint) and is expected to return an array of objects as well. Here is the interface implementation:

javascript
module.exports = (entries) => {
  return entries
}

Single file override ​

Let's consider an example with the following given conditions:

  • An attribute for floor label is not present in LDAP;
  • Most of the entries in LDAP have a defined userWorkstation attribute which is the desk number;
  • Floor label is encoded in the desk number in the format AA-000, where AA is a floor label and 000 is the actual desk number on the floor.

Out goal:

  • Use userWorkstation attribute as locationId in Deskradar as defined in LDAP;
  • Derive floor label from the desk number and use it as floorLabel column in Deskradar;
  • Ignore all LDAP entries which have empty userWorkstation attribute.

To achieve that, create a file on the host machine named middleware.js with the following content:

javascript
module.exports = (entries) => {
  return entries.reduce((acc, entry) => {
    // Ignore entries with no userWorkstations attribute
    if (!entry.userWorkstations) {
      return acc
    }

    // Split the userWorkstations attribute
    const derivedFloorLabel = entry.userWorkstations.split('-').shift()

    acc.push({ ...entry, derivedFloorLabel })
    return acc
  }, [])
}

The middleware function will:

  • skip the entries with an empty userWorkstations attribute;
  • split the value of the userWorkstations attribute accordingly to the defined format and set the value of the new derivedFloorLabel field added to the entry as if it was received from the LDAP;
  • pass the modified data to the CSV export and data push steps of the pipeline.

Next, create config.json file with the following configuration. Notice the new attribute derivedFloorLabel added to the attributes field, and floorLabel column added to the columns field (required if you want use the push csv command instead of export).

json
{
  "ldapUri": "ldaps://10.0.0.24:636",
  "baseDn": "ou=DemoUsers100,dc=contoso,dc=com",

  "ldapUsername": "<username>",
  "ldapPassword": "<password>",

  "attributes": "displayName,userPrincipalName,physicalDeliveryOfficeName,derivedFloorLabel,userWorkstations",
  "columns": "displayName,email,buildingName,floorLabel,locationId",

  "format": "csv",
  "output": "data/output.csv"
}

Now let's run the application. We'll mount the middleware file to the Docker container on the /app/data-middleware/index.js path.

shell
docker run --rm \
  -v $(pwd)/middleware.js:/app/data-middleware/index.js \
  -v $(pwd)/config.json:/app/config/local.json \
  -v $(pwd)/data:/app/data \
  ghcr.io/deskradar/ldap-companion:2 export

This will create a output.csv file in the host ./data directory with the columns:

  • displayName
  • userPrincipalName
  • physicalDeliveryOfficeName
  • derivedFloorLabel
  • userWorkstations

This file can be imported via Deskradar user interface.

To push data directly to Deskradar, replace export command with push csv and provide access credentials to your Deskradar site accordingly to the documentation.