Use LDAP Client to Delete AD User Accounts with Leaf Objects

When deleting an AD account that has leaf objects, IdentityIQ will throw an exception of “The directory service can perform the requested operation only on a leaf object” . Currently, the AD connector only supports deleting a single object in Active Directory. It does not support deleting a parent object which has one or more child objects.

One solution is to use ldap api to delete the AD account recursively from Java code. Below is a Java code example:

package xxxxxx.connector.activedirectory;

import org.apache.log4j.Logger;

import netscape.ldap.LDAPConnection;

import netscape.ldap.LDAPEntry;

import netscape.ldap.LDAPException;

import netscape.ldap.LDAPSearchConstraints;

import netscape.ldap.LDAPSearchResults;

import netscape.ldap.LDAPv3;

public class LDAPClient {

private static final Logger logger = Logger.getLogger(LDAPClient.class);

private String host;

private int port;

private String userId;

private String password;

private LDAPConnection con;

public LDAPClient(String host,int port,String userId, String password){

this.host=host;

this.port=port;

this.userId=userId;

this.password=password;

}

private LDAPConnection getConnection(){

LDAPConnection con = new LDAPConnection();

try {

con.connect(this.host, this.port, this.userId, this.password);

} catch (LDAPException e) {

logger.error(“Failed to mconnect to ldap server”, e);

}

return con;

}

public void connect(){

this.con = getConnection();

}

public void disconnect(){

if(this.con != null && this.con.isConnected()){

try {

this.con.disconnect();

} catch (LDAPException e) {

logger.error(“Failed to disconnect from ldap server”, e);

}

}

}

//The delete method will delete the user account and child leaf objects recursively

public void delete(String dn) throws IllegalArgumentException,RuntimeException{

if(dn == null){

throw new IllegalArgumentException(“Missing dn”);

}

if(this.con == null){

throw new RuntimeException(“Not connected to ldap server”);

}

String theDN = “”;

LDAPSearchConstraints searchConstraints = con.getSearchConstraints();

// Retrieve all results at once

searchConstraints.setBatchSize( 0 );

try {

// Find all immediate child nodes

LDAPSearchResults res =con.search( dn,LDAPConnection.SCOPE_ONE,”objectclass=*”,new String[] {LDAPv3.NO_ATTRS},false,searchConstraints );

// Recurse on entries under this entry

while ( res.hasMoreElements() ) {

try {

// Next directory entry

LDAPEntry entry = res.next();

theDN = entry.getDN();

// Recurse down

delete( theDN);

} catch ( LDAPException e ) {

logger.error(“Failed to iterate child nodes.”,e);

throw new RuntimeException(“Failed to iterate child nodes. Error message: “ + e.getLDAPErrorMessage());

}

}

try{

con.delete(dn);

}catch(LDAPException e){

logger.error(“Failed to delete [“ + dn + “]”, e);

throw new RuntimeException(“Failed to delete [“ + dn + “]. Error message: “ + e.getLDAPErrorMessage());

}

} catch (LDAPException e) {

logger.error(“Failed to to search child nodes.”,e);

throw new RuntimeException(“Failed to to search child nodes. Error message: “ + e.getLDAPErrorMessage());

}

}

}

The code is called from our termination workflow.