AEM Automatic User Synchronization With LDAP

Bobby Mavrov4 Comments

AEM offers easy synchronization with LDAP providers like Active Directory. Once a user is added to the Active Directory group holding users with AEM access and after all settings are applied correctly all that needs to be done is an Admin to run the syncAllExternalUsers() method of the External Identity Synchronization Management from the JMX console.

Let’s see how we can automate the above manual method. Once we achieve it, all updates in the Active Directory groups related to AEM will be automatically applied to the platform. 

An easy way to make it possible is by using scheduled service that triggers syncAllUsers() method of the External Identity Synchronization Management  mbean. Before we start let’s review the 3 components, we need to make this run successfully:

  1. All user synchronization settings need to be implied correctly so we have access to the Active Directory. It is important to have the user.autoMembership property of the DefaultSyncHandler set to AEM user group that will act as a default group with basic access for every new user.
  2. We need to have a default access user group in AEM with the minimum access allowed. All new or existing users have to be members of this group. All other user groups also will need to be members of this basic access group. This way they can overwrite the access restrictions imposed by it.
  3. We need to create a scheduled service in the backend to access the Mbean Server and run syncAllUsers() at some interval

Step I: Setting up the 3 components required so that our user synchronization with LDAP is active

Example: Synchronization Handler Configuration

Example: Synchronization Handler Configuration

Here, it is important to set user.autoMembership to a default group with basic access rights that all users will be members of. We could use group dam-users as example. All basic restrictions will have to be applied to this group and all other groups will have to be members of this group in order to inherit them. If you don’t want regular users to have access to nodes meant for Power Users you can deny the access to them for dam-users, make power-users group member of dam-users and then allow the access for power-users specifically.

All newly synced users will be automatically added as members of dam-users. If you need a specific new user to be members of group with higher privileges you’ll have to either manually add them after they’ve been synced or expend the configuration of the Identity Provider and Configuration Handler to map LDAP groups to specific AEM user groups.

Example: External Login Module Configuration

Step II: Using Basic Access User Group

As mentioned above we need a basic user group that all users will be members of as well as all other groups. The member groups will overwrite the access restriction of this basic group. New members will be granted basic access when synced via our scheduled service so administrator won’t have to be involved unless new user needs to be added to group with higher level access. For example:

User John is meant to have basic read-only access:

  • When synced he’ll be automatically be added to a default read-only dam-users group.
  • No further action is required by admin.

User Jim needs to have Modify and Create access over /content/dam:

  • This access is provided by the power-users group.
  • Power-users is member of dam-users but also has Modify and Create access set over /content/dam.
  • Jim is added to dam-users automatically when synced. Admin will have to add him to power-users afterwards as well.

Step III: Creating a Scheduled Service that runs org.apache.jackrabbit.oak: External Identity Synchronization Management

Example code:

package my.project.scheduled;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.AttributeType;
import org.osgi.service.metatype.annotations.Designate;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
* Service to invoke the syncAllUsers() method of org.apache.jackrabbit.oak
* so AEM users can be synced with LDAP.
* */
     immediate = true,
     configurationPid = "my.project.scheduled.SyncUsersService"
@Designate(ocd = SyncUsersService.Configuration.class)
public class SyncUsersService implements Runnable{
  protected static Logger logger = LoggerFactory.getLogger(SyncUsersService.class);
  public void activate(Configuration config){}
   * Runs the implementation at the scheduled interval
   * @return void
   * */
  public void run() {"Starting LDAP Sync Service");
     MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
     ObjectName objectName = null;
     try {
        objectName = new ObjectName("org.apache.jackrabbit.oak:handler=\"Active Directory\","
              + "idp=\"Active Directory\",name=External Identity Synchronization Management,type=UserManagement");
        mBeanServer.invoke(objectName, "syncAllUsers", new Object[]{true},
              new String[]{boolean.class.getName()});
     } catch (Exception e) {
        logger.error("Error while running the Mbean to sync users with LDAP. ", e);
  @ObjectClassDefinition(name="LDAP User Sync Service")
  public @interface Configuration {
           name = "Expression",
           description = "Cron-job expression. Default: run every 30 min.",
           type = AttributeType.STRING)
     String scheduler_expression() default "0 */30 * ? * *";

Some main points here:

  • The service is registered as OSGi component with modifiable settings that include the scheduler.expression as String holding cron expression. In our case the service will run every 30 min.
  • We need to instantiate MbeanServer object via ManagementFactory

MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();

  • We need to instantiate ObjectName and assign it with

objectName = new ObjectName(“org.apache.jackrabbit.oak:handler=\”Active Directory\”, idp=\”Active Directory\”,name=External Identity Synchronization Management,type=UserManagement”);

  • We need to invoke syncAllUsers() with parameter false or true depending on weather we want to keep or delete users no longer existing in LDAP.

mBeanServer.invoke(objectName, “syncAllUsers”, new Object[]{false}, new String[]{boolean.class.getName()});

After all this all newly added users to the LDAP group we are monitoring we be created and added to the dam-users basic access group. Users removed from LDAP will be either removed or disabled in AEM, depending on the settings we choose.

KBWEB Consult specializes in customizing and integrating the Adobe Experience Manager (AEM) Platform. Contact us for a free consultation.


4 Comments on “AEM Automatic User Synchronization With LDAP”

  1. Bob, syncallexternalusers() is not updating user credentials. What could be causing this ?
    I have to manually go in and delete the user from useradmin and then sync syncallexternalusers() again to get updated credentials.

    1. Hi randi,

      Initially we had to use syncAllUsers(true) instead of syncAllExternalUsers() possible for the same reason. Though, syncAllExternalUsers() was actually working as it was supposed to when running it manually for the /system/console/jmx it did not update users when ran from similar component. Later on, however, we had switch back to syncAllExternalUsers() as we noticed syncAllUsers(true) did not work on the latest 6.3 version, again not sure why. syncAllExternalUsers() is also working fine for 6.5.8 again.

      So in your case users are created/removed successfully but the change in their credentials (password) do not get reflected?


  2. Bob,
    Thanks for the detailed information.

    I am stuck at two points, in second config DefaultSyncHandler
    1. RFC7613 username Normalization profile
    2. User Dynamic Membership

    if we enabled both configuration, what will the the impact.

    I am not getting any information about these two anywhere, please help to clear.

    Thanks in advance.

    1. Hi Punit,

      We’ve not have to use any of those 2 available configurations. It seems that the first one is to enforce the handling of Unicode strings representing username and password in cases of internationalized usernames and passwords (more information here – The second one seems to be regarding Dynamic Groups which allow determining of user membership using LDAP search expressions (more information can be found here –

      We tested having these configurations enabled in the setup described in this article and there was no effect on its functionality.

Leave a Reply