AEM Automatic User Synchronization With LDAP

AEM offers easy synchronization with LDAP providers like Active Directory. Once a user is added to 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;
 
import javax.management.MBeanServer;
import javax.management.ObjectName;
import java.lang.management.ManagementFactory;
 
 
/**
* Service to invoke the syncAllUsers() method of org.apache.jackrabbit.oak
* so AEM users can be synced with LDAP.
* */
@Component(
     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);
 
  @Activate
  public void activate(Configuration config){}
 
  /**
   * Runs the implementation at the scheduled interval
   *
   * @return void
   * */
  @Override
  public void run() {
     logger.info("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 {
 
     @AttributeDefinition(
           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.

Leave a Reply