. . .

LDAP Module

Introduction

This module synchronizes users from LDAP sources into ApiOmat LDAPUsers and LDAPGroups. LDAPUser is a subclass of User and can be used to authenticate within an application or via REST. For authorization purposes, these users may be members of LDAPGroups, a subclass of Role. The authentication is done directly against the LDAP directory.

Configuration

Server Hostname(s)

Hostname(s) or IP(s) of the LDAP server(s), comma separated

Server Port(s)

Port(s) of the LDAP server(s), comma separated, default value is 636 if LDAPS is enabled or 389 if not.

Bind DN

User for bind operation, leave empty for anonymous access

Bind DN password

User password for bind operation

Base DN

Root node of LDAP Directory

User filter

Filter to get all Users

User ID

LDAP attribute name which contains a user ID, this field will be used for the "userName" field in ApiOmat, default is sAMAccountName

Module of User class (optional)

If you want to use your own subclass of LDAPUser, insert your subclasse's module's name here so you can sync users to it.

User class name (optional)

If you want to use your own subclass of LDAPUser, insert your subclasse's name here so you can sync users to it.

Activate sync LDAP groups

If set to true (default), the synchronization will include LDAP groups

Group filter

Filter to get all groups

Group name attribute

The attribute that identifies a group's name. Default is "cn".

Attributes holding member information

Attributes holding distinguished names of group members, separated by comma

Module of Role class (optional)

If you want to use your own subclass of LDAPGroup, insert your subclass's module's name here so you can sync groups to it.

The user's group attribute name

The attribute of an LDAPUser that identifies group memberships of this user. Default is "distinguishedname".

Role class name (optional)

If you want to use your own subclass of LDAPGroup, insert your subclass's name here so you can sync groups to it.

Write user attributes map

If set to true (default), all attributes will be written to the "userAttributes" map of the LDAP user (in addition to the fields that match the attribute names)

Disable auth for the sync

If set to true (default), no auth checks will be done during user synchronization. This increases the synchronization speed.
As the internal actions in a native module (findBy, save and delete) are usually done with backend owner permissions, this should not be harmful.
If you use custom role and auth check methods and explicitly want these methods to be called during synchronization, then you have to set this flag to false.

Log all messages async

If set to true (default), all messages of the synchronization process will be logged asynchronously.

Overwrite missing attributes

If set to true (defaults to false), each field of the class will be set to null if the respective attribute does not exist (or is empty) in LDAP.
This does not apply to the general attributes (like "allowedRolesRead") and all attributes which the User and LDAPUser classes have. It only applies to the values of the "userAttributes" map of LDAPUser and custom attributes of classes that inherit from LDAPUser.
If set to false, additional values (or values that existed on an LDAP entry and have been removed) will stay on the object in ApiOmat. This can be used to enrich the data of the synchronized users with additional values, e.g. from other systems.

Use LDAPS

If set to true (defaults to false), all connections to your LDAP server(s) will be encrypted.

Certificate for LDAPS

The SSL public certificate of your LDAP server. Required when using LDAPS - upload the certificate file in this field.

Module setup

Fill in the values fitting to your directory. An example would be:

Server Hostname

ldap.example.com

Server Port

389

Bind DN

uid=admin,ou=system

Bind DN password

123456

Base DN

OU=com,DC=mycompany,DC=local

User filter

(objectCategory=Person)

User ID

uid

Group filter

(objectClass=group)

Group name attribute

cn

Attributes holding member information

uniquemember,member

Custom user class

You can define a custom user class which the LDAP users will get synced to. To do so, you have to create a class that inherits from the LDAPUser class in the LDAP module and then set your class's name and module name in the module configuration, in the fields User class name and Module of User class respectively.

You can add additional attributes that match the attribute names for your entities on the LDAP server. The values of these attributes will be automatically mapped on the synchronized objects. If you only need the attributes that exist on your class and don't want to have all attributes stored in the userAttributes attribute of the LDAPUser, you can set the Write user attributes map flag to false in your module configuration. This may speed up the synchronization process a bit and saves bandwidth when retrieving the users within a frontend.

Custom role class

You can define a custom class for LDAP groups in the same way as for LDAP users - create a class that inherits from LDAPGroup and set it's name and module name in the module configuration, in the fields Role class name and Module of Role class respectively.

The name attribute of the respective objects will be populated with the value of the attribute whose name can be configured with the property Group name attribute.

LDAPS

To use LDAP with encryption (LDAPS), first enable it on your server and generate an SSL certificate for said server.
Upload this certificate in the module configuration field "Certificate for LDAPS", and set the flag "Use LDAPS" to true. You will also have to set the port if you are not using the default of 636.

Now all connections to your server will be completely encrypted with TLS.

Synchronization

The synchronization process consists of four tasks.

  1. Import all users that exist on the LDAP server as instances of LDAPUser (or whichever class you've set in your configuration). Users that already exist will be updated if there are changes on the LDAP user.

  2. Check every existing ApiOmat user of the configured class to see if they still exist on the LDAP server. If they don't exist anymore, they will be deleted from ApiOmat.

  3. If the module configuration property Activate sync LDAP groups is set to true, groups from the LDAP server are imported as instances of LDAPGroup (or whichever class you've set in your configuration) in the same manner as users. Also, names of users imported in the previous part are added to the members list of the respective LDAPGroup, using the module configuration property Attributes holding member information.

  4. If the module configuration property Activate sync LDAP groups is set to true, check every existing ApiOmat group of the configured class to see if it still exists on the LDAP server. If it doesn't exist anymore, it will be deleted from ApiOmat.

If your LDAP server is not available when the process is executed, it will be aborted and the data on ApiOmat will remain unchanged. If there is an error during the creation, update or deletion of a single user (e.g. through an already existing user with the same user name in another class) the error will be logged and the synchronization will proceed with the next user.

If more than one LDAP server is configured, the module tries to connect to each server until it finds a working connection. The first working connection is then used for synchronization. The list of ports are related to the hostnames. If no ports are given, the default port will be used - 636 if LDAPS is enabled, 389 if not.
Otherwise, you have to write the ports in the corresponding order of the hostnames. For instance, if you have one ldap server on ldap1.yourcompany.com listening on port 489 and another server ldap2.yourcompany.com on port 589, you have to enter "ldap1.yourcompany.com,ldap2.yourcompany.com" in the Server hostname configuration field and "489,589" in the ports configuration field.

Use

All you have to do is configure the directory and wait until the next synchronization, which is done every hour. You can also manually start the synchronization via the MyModule page in dashboard or via REST:

  curl -v $HOST/yambas/rest/modules/LDAP/v/$MODULEVERSION/$APPNAME/spec/sync/$APPNAME -u $USER:$PASSWORD

After a successful synchronization, you have to set the LDAPUser class (or whichever class you've set in your configuration) as the Authentication class in your backend configuration to authenticate to your LDAP server. We will then check the credentials against your LDAP server. Please note that it has to be done this way as we cannot synchronize the passwords of the users.

Your imported LDAPGroup's names may then be used in ApiOmat's access control lists of any class.

User Authentication via OAuth2 Tokens

The synchronized users are objects of the class LDAPUser, which inherits from the User class in the Basics module. So you can make use of the existing OAuth2 functionality and e.g. send a request to "YOURHOST/yambas/oauth/token" to get an access token for the user. For more info about how this works in ApiOmat, see here: ApiOmat and OAuth2.

In the case of LDAP, you might want to force the user to authenticate against the LDAP server as soon as the access token is expired, instead of allowing them to use the previously received refresh token. To do this, just change the value yambas.oAuth2TokenValiditySeconds.standard.refresh in your apiomat.yaml file to 0, or if you want refresh tokens to work except for LDAP, you can manually set the refresh token expiry in every request when fetching a token.

Healthcheck

The LDAP module provides a healthcheck, for more general info about how they work in ApiOmat, see Health checks. This healthcheck returns 0 (which means it's healthy), when the module is able to establish a functional connection to or more of the given hosts, otherwise 1.

Additionally, we have a custom healthcheck, which is reachable at:

curl $HOST/yambas/rest/modules/$MODULENAME/v/$MODULEVERSION/$APPNAME/spec/healtheck/ -u $USER:$PASSWORD

Note: in this case, the user has to be an ApiOmat customer.

This will return a JSON, which will look like this when it's healthy:

{
"<URL-OF-LDAP>:<PORT-OF-LDAP>":
{
"isReachable":true,
"isCredentialsValid":true,
"isUserLocked":false,
"isHealthy":true
}
}