Appearance
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
- LDAP is enabled on your domain controller
- Worker node to run the application
- Docker is installed on the worker node
- Worker node can access your LDAP server
- Worker node can reach your Deskradar instance
- 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.
- In the sidebar, select Team, then open the API Keys tab.
- Select New API key.
- Enter a name that identifies the purpose of the key, such as
LDAP companion. - Set Role to Editor. The form preselects Viewer, and a key with that role cannot start an import.
- 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.
- 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:2Every 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.
| Tag | What it points to |
|---|---|
2 | the newest version 2 release |
2.0 | the newest 2.0.x release |
2.0.1 | that exact build, forever |
latest | the 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 loadRunning 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:2bash
docker run --rm ghcr.io/deskradar/ldap-companion:2 helpbash
docker run --rm ghcr.io/deskradar/ldap-companion:2 <command> --helpFile 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.csvThe 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:
| Remove | Add |
|---|---|
--site-email, --site-password | --api-key |
CONF_SITE_EMAIL, CONF_SITE_PASSWORD | CONF_API_KEY |
siteEmail, sitePassword | apiKey |
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:2Your 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 staffto 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 staffStep 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:
| Message | Cause | What to do |
|---|---|---|
the API key is missing, invalid or revoked | The key is mistyped, expired or deleted. | Create a new key and update your configuration. |
the API key needs the "editor" or "admin" role | The 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 denied | A 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
exportcommand downloads the data from the LDAP server and saves it locally as a CSV or JSON file.push csvcommand uploads the data from a local CSV file to your Deskradar instance.push ldapcommand upload the data from your LDAP server to your Deskradar instance.
Configuration
The application can be configured using following options:
- Command line parameters
- Environment variables
- 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.csvExample 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 staffEvery 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 exportConfigure 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 exportConfiguration Parameters
Configure logging
| Command line argument | Environment variable | JSON configuration file key name |
|---|---|---|
--quiet or --verbose | LOG_LEVEL | logLevel |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--ldap-username <string> | CONF_LDAP_USERNAME | ldapUsername |
Username for LDAP server connection.
Default: empty
Commands: export, push csv, push ldap
LDAP password
| Command line argument | Environment variable | JSON configuration file key name |
|---|---|---|
--ldap-password <string> | CONF_LDAP_PASSWORD | ldapPassword |
Password for LDAP server connection.
Default: empty
Commands: export, push csv, push ldap
Base DN
| Command line argument | Environment variable | JSON configuration file key name |
|---|---|---|
--base-dn <string> | CONF_BASEDN | baseDn |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--ldap-filter <string> | CONF_LDAP_FILTER | ldapFilter |
Search query for LDAP search.
Example: (&(physicalDeliveryOfficeName=Chicago)(department=ExampleDepartment))
Default: empty
Commands: export, push csv, push ldap
LDAP URI
| Command line argument | Environment variable | JSON configuration file key name |
|---|---|---|
--ldap-uri <string> | CONF_LDAP_URI | ldapUri |
URL of the LDAP server.
Example: ldaps://10.0.0.24:636
Default: empty
Commands: export, push csv, push ldap
Format
| Command line argument | Environment variable | JSON configuration file key name |
|---|---|---|
--format <string> | CONF_FORMAT | format |
Format in which to save the exported LDAP data. Valid values: json or csv.
Default: json
Commands: export
Output
| Command line argument | Environment variable | JSON configuration file key name |
|---|---|---|
--output <string> | CONF_OUTPUT | output |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--attributes <list> | CONF_ATTRIBUTES | attributes |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--uuid-attributes <list> | CONF_UUID_ATTRIBUTES | uuidAttributes |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--base64-attributes <list> | CONF_BASE64_ATTRIBUTES | base64Attributes |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--site-uri <string> | CONF_SITE_URI | siteUri |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--api-key <string> | CONF_API_KEY | apiKey |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--file <string> | CONF_FILE | file |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--columns <list> | CONF_COLUMNS | columns |
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 name | Required for resource types | Resource types | Validations | Notes |
|---|---|---|---|---|
buildingName | any | any | string, max length 20 characters | Building names must be unique on your Deskradar instance. |
floorLabel | any | any | string, max length 3 characters | Floor labels must be unique within every building on your Deskradar instance. |
locationId | Required: desks, rooms, utilities. Optional: staff | any | string, max length 36 characters, regex: /^[a-zA-Z0-9_\.\:\/\\-]+$/ | Identifies the location of the marker. |
email | staff | any | string, valid email | Email identifies staff marker and must be unique for resource type staff. |
firstName | optional | staff | string, max length 48 characters | Person first name |
lastName | optional | staff | string, max length 48 characters | Person last name |
displayName | optional | any | string, max length 100 characters | Value is used for the marker name. If not defined, firsName and lastName will be combined to construct the resulting name. |
role | optional | any | string, max length 100 characters | Comma separated list of strings can used. |
status | optional | any | string, must be one of available, unavailable or remote (only for resource type staff) | Marker status. Default: available. |
statusText | optional | any | string, max length 140 characters | Marker status text |
nickname | optional | staff | string, max length 100 characters | Person nickname |
url | optional | any | string, max length 100 characters | URL of the relevant website or resource details page |
skype | optional | any | string, max length 100 characters | Skype username |
twitter | optional | any | string, max length 100 characters | Twitter handle |
linkedin | optional | any | string, max length 100 characters | LinkedIn profile |
phoneOffice | optional | any | string, max length 100 characters | Office phone number |
phoneMobile | optional | any | string, max length 100 characters | Mobile phone number |
notes | optional | any | string, max length 1000 characters | Marker notes |
deskType | optional | desks | string, must be one of spare, hot | Default: spare |
Example: displayName,email,buildingName,floorLabel,locationId
Default: displayName,email
Commands: push csv, push ldap
Resource
| Command line argument | Environment variable | JSON configuration file key name |
|---|---|---|
--resource <string> | CONF_RESOURCE | resource |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--attributes-update-mode <string> | CONF_ATTRIBUTES_UPDATE_MODE | attributesUpdateMode |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--remove-unmatched-mode <string> | CONF_REMOVE_UNMATCHED_MODE | removeUnmatchedMode |
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 argument | Environment variable | JSON configuration file key name |
|---|---|---|
--override-json <string> | CONF_OVERRIDE_JSON | overrideJson |
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
userWorkstationattribute which is the desk number; - Floor label is encoded in the desk number in the format
AA-000, whereAAis a floor label and000is the actual desk number on the floor.
Out goal:
- Use
userWorkstationattribute aslocationIdin Deskradar as defined in LDAP; - Derive floor label from the desk number and use it as
floorLabelcolumn in Deskradar; - Ignore all LDAP entries which have empty
userWorkstationattribute.
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
userWorkstationsattribute; - split the value of the
userWorkstationsattribute accordingly to the defined format and set the value of the newderivedFloorLabelfield 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 exportThis will create a output.csv file in the host ./data directory with the columns:
displayNameuserPrincipalNamephysicalDeliveryOfficeNamederivedFloorLabeluserWorkstations
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.