#1 2017-03-28 13:08:48

Sreejith S
Member
Registered: 2016-11-16

LDAP Sync to Red Hat Directory Server

Hi,

we are facing issues with connecting LDAP, we are able to get the search result using the command ldapsearch in the terminal.

Following is the error message while executing the ldapimport.groovy file and also a folder is getting created

-----------------------------
Script execution failed.
error message: javax.script.ScriptException: java.lang.RuntimeException: Error processing search result: cn=John Doe,ou=people,o=customer1,dc=munidev,dc=org (java.lang.RuntimeException)
script arguments:
file: ldapimport_LK20170327152203UTC.groovy (id: 846344, line 452)
line number: 452 (66, 29, 243)
line: loadFromDirectory();
---------------------------

Following is my ldapimport.groovy script

---------------------------
import java.util.Map.Entry
import java.util.logging.Level
import java.util.logging.Logger

import javax.inject.Inject
import javax.naming.Context
import javax.naming.NamingEnumeration
import javax.naming.NamingException
import javax.naming.directory.Attribute
import javax.naming.directory.DirContext
import javax.naming.directory.InitialDirContext
import javax.naming.directory.SearchControls
import javax.naming.directory.SearchResult
import javax.naming.ldap.LdapName

import net.datenwerke.rs.scripting.service.scripting.scriptservices.GlobalsWrapper
import net.datenwerke.rs.terminal.service.terminal.TerminalService
import net.datenwerke.rs.utils.jpa.EntityUtils
import net.datenwerke.security.client.login.AuthToken
import net.datenwerke.security.service.authenticator.hooks.PreAuthenticateHook
import net.datenwerke.security.service.authenticator.hooks.adapter.PreAuthenticateHookAdapter
import net.datenwerke.security.service.usermanager.UserManagerService
import net.datenwerke.security.service.usermanager.entities.AbstractUserManagerNode
import net.datenwerke.security.service.usermanager.entities.Group
import net.datenwerke.security.service.usermanager.entities.OrganisationalUnit
import net.datenwerke.security.service.usermanager.entities.User


GLOBALS.getInstance(LdapRunner.class).run(GLOBALS);


public class LdapRunner {
   
    private UserManagerService userManagerService;
    private EntityUtils entityUtils;

    @Inject
    public LdapRunner(
            UserManagerService userManagerService,
            EntityUtils entityUtils
        ){
            this.entityUtils = entityUtils;
            this.userManagerService = userManagerService;
    }
   
    public void run(GlobalsWrapper GLOBALS){
        LdapUserLoader lul = new LdapUserLoader(entityUtils, userManagerService);
         lul.setProviderUrl("ldap://ip_addrs:port");
          lul.setSecurityPrincipal("cn=admin,cn=managers,dc=munidev,dc=org");
          lul.setSecurityCredentials("password");
              lul.setLdapBase("ou=people,o=customer1,dc=munidev,dc=org");
       
     
      def terminal = GLOBALS.getInstance(TerminalService.class)
         OrganisationalUnit targetNode  = terminal.getObjectByLocation("/usermanager/externalk", false)
       
       
        if(null == targetNode){
            AbstractUserManagerNode umRoot = userManagerService.getRoots().get(0);
            targetNode = new OrganisationalUnit("externalk");
            umRoot.addChild(targetNode);
            userManagerService.persist(targetNode);
        }
       
        lul.setTargetNode(targetNode);
        lul.run();
    }
}


public class LdapUserLoader {

    private final Logger logger = Logger.getLogger(getClass().getName());


    private String ldapBase;
    private String ldapFilter = "(|(objectClass=person)(objectClass=inetUser)(objectClass=organizationalPerson)(objectClass=inetOrgPerson))";

    private String providerUrl;
    private String securityCredentials;

    private String securityPrincipal;
    private OrganisationalUnit targetNode;

    private boolean includeNamespace = false;

    private Map<String, AbstractUserManagerNode> guidMap;
    private Map<LdapName, AbstractUserManagerNode> nodesInDirectoryByName;
    private Map<String, AbstractUserManagerNode> nodesInDirectoryByGuid;
    private TreeMap<LdapName, SearchResult> searchResults;

    private List<AbstractUserManagerNode> removedNodes;
    private List<AbstractUserManagerNode> addedNodes;

    private EntityUtils entityUtils;
    private UserManagerService userManagerService;

    private class AdGUID {
        byte[] bytes;

        public AdGUID(byte[] bytes) {
            this.bytes = bytes;
        }

        private void addByte(StringBuffer sb, int k) {
            if(k<=0xF)
                sb.append("0");
            sb.append(Integer.toHexString(k));
        }

        @Override
        public String toString() {
            StringBuffer sb = new StringBuffer();
            addByte(sb, (int)bytes[3] & 0xFF);
            addByte(sb, (int)bytes[2] & 0xFF);
            addByte(sb, (int)bytes[1] & 0xFF);
            addByte(sb, (int)bytes[0] & 0xFF);
            sb.append("-");
            addByte(sb, (int)bytes[5] & 0xFF);
            addByte(sb, (int)bytes[4] & 0xFF);
            sb.append("-");
            addByte(sb, (int)bytes[7] & 0xFF);
            addByte(sb, (int)bytes[6] & 0xFF);
            sb.append("-");
            addByte(sb, (int)bytes[8] & 0xFF);
            addByte(sb, (int)bytes[9] & 0xFF);
            sb.append("-");
            addByte(sb, (int)bytes[10] & 0xFF);
            addByte(sb, (int)bytes[11] & 0xFF);
            addByte(sb, (int)bytes[12] & 0xFF);
            addByte(sb, (int)bytes[13] & 0xFF);
            addByte(sb, (int)bytes[14] & 0xFF);
            addByte(sb, (int)bytes[15] & 0xFF);

            return sb.toString();
        }

    }

    public LdapUserLoader(EntityUtils entityUtils, UserManagerService userManagerService) {
        this.entityUtils = entityUtils;
        this.userManagerService = userManagerService;
    }


    public String getLdapBase() {
        return ldapBase;
    }

    public String getProviderUrl() {
        return providerUrl;
    }

    public String getSecurityCredentials() {
        return securityCredentials;
    }

    public String getSecurityPrincipal() {
        return securityPrincipal;
    }

    public void setLdapBase(String ldapBase) {
        this.ldapBase = ldapBase;
    }

    public void setProviderUrl(String providerUrl) {
        this.providerUrl = providerUrl;
    }

    public void setSecurityCredentials(String securityCredentials) {
        this.securityCredentials = securityCredentials;
    }

    public void setSecurityPrincipal(String securityPrincipal) {
        this.securityPrincipal = securityPrincipal;
    }

    public void setTargetNode(OrganisationalUnit targetNode) {
        this.targetNode = targetNode;
    }

    public boolean isIncludeNamespace() {
        return includeNamespace;
    }

    public void setIncludeNamespace(boolean includeNamespace) {
        this.includeNamespace = includeNamespace;
    }

    public String getLdapFilter() {
        return ldapFilter;
    }

    public void setLdapFilter(String ldapFilter) {
        this.ldapFilter = ldapFilter;
    }
 
    private Properties compileProperties(){
        Properties props = new Properties();

        props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.setProperty(Context.PROVIDER_URL, providerUrl);
        props.setProperty(Context.URL_PKG_PREFIXES, "com.sun.jndi.url");
        props.setProperty(Context.REFERRAL, "throw");
        props.setProperty(Context.SECURITY_AUTHENTICATION, "simple");

        props.setProperty(Context.SECURITY_PRINCIPAL, securityPrincipal);
        props.setProperty(Context.SECURITY_CREDENTIALS, securityCredentials);

        /* return these as binary */
        props.put("java.naming.ldap.attributes.binary","objectGUID");
        return props;
    }

    private void createGuidMap(AbstractUserManagerNode current) {
        Map<String, AbstractUserManagerNode> map = new HashMap<>();
        createGuidMap(current, map );

        guidMap = map;
    }

    private void createGuidMap(AbstractUserManagerNode current, Map<String, AbstractUserManagerNode> map){
        map.put(current.getGuid(), entityUtils.unproxy(current));

        for(AbstractUserManagerNode cn : current.getChildren()){
            createGuidMap(cn, map);
        }
    }

    private String getStringAttribute(SearchResult sr, String attributeName) throws NamingException{
        try{
            return sr.getAttributes().get(attributeName).get().toString();
        }catch(Exception e){
            logger.log(Level.WARNING,"failed to retrieve attribute '" + attributeName + "' from " + sr.getNameInNamespace(), e);
            return null;
        }
    }

   private String getGuid(SearchResult sr) throws NamingException{
    try{
        return sr.getAttributes().get("uidNumber").get().toString();
    }catch(Exception e){
        throw new RuntimeException("failed to retrieve objectGUID from " + sr.getNameInNamespace(), e);
    }
}

    private void loadFromDirectory() throws NamingException {
        Properties props = compileProperties();
        String originBase = this.providerUrl.endsWith("/")?providerUrl:providerUrl + "/";

        this.nodesInDirectoryByName = new HashMap<>();
        this.nodesInDirectoryByGuid = new HashMap<>();
        this.addedNodes = new ArrayList<>();
        this.removedNodes = new ArrayList<>();

        DirContext ctx = null ;

        try {
            ctx = new InitialDirContext(props);

            SearchControls searchControls = new SearchControls();
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            LdapName ldapBaseName = new LdapName(getLdapBase());
            NamingEnumeration<SearchResult> results = ctx.search(ldapBaseName, this.ldapFilter, searchControls);

            /* order search results by name to make sure children never get processed before their parent */
            searchResults = new TreeMap<>();
            while (results.hasMoreElements()) {
                SearchResult sr = (SearchResult) results.next();
                searchResults.put(new LdapName(sr.getNameInNamespace()), sr);
            }

            for(SearchResult sr : searchResults.values()){
                try {
                    LdapName nodeName = new LdapName(isIncludeNamespace() ? sr.getNameInNamespace() : sr.getName());
                    LdapName nodeNameInNamespace = new LdapName(sr.getNameInNamespace());

                    /* skip empty nodes */
                    if(nodeName.size() == 0)
                        continue;


                    /* get parent node */
                    LdapName parentName = (LdapName) nodeNameInNamespace.getPrefix(Math.max(0, nodeNameInNamespace.size() - 1));
                    AbstractUserManagerNode parent = this.nodesInDirectoryByName.get(parentName);
                    if(null == parent){
                        if(parentName.equals(new LdapName(ldapBase))){
                            /* root node */
                            parent = targetNode;
                        }else{
                            throw new IllegalStateException("Missing parent for " + sr.getNameInNamespace());
                        }
                    }

                    /* create node */
                    Attribute objectClass = sr.getAttributes().get("objectClass");
                    AbstractUserManagerNode umNode = null;
                    if(objectClass.contains("person")) {
                        umNode = createOUNode(sr, parent);

                    } else if(objectClass.contains("inetUser")) {
                        umNode = createUserNode(sr, parent);

                    } else if(objectClass.contains("inetOrgPerson")){
                        umNode = createGroupNode(sr, parent);
                    } else continue;

                    /* set common attributes */
                    umNode.setWriteProtection(false);
                    umNode.setGuid(getGuid(sr));
                    umNode.setOrigin(originBase + sr.getNameInNamespace());

                    nodesInDirectoryByName.put(new LdapName(sr.getNameInNamespace()), umNode);
                    nodesInDirectoryByGuid.put(getGuid(sr), umNode);
                }catch(Exception e){
                    throw new RuntimeException("Error processing search result: " + sr.getNameInNamespace() , e);
                }
            }


        }finally{
            try {
                if(null != ctx)
                    ctx.close();
            } catch (NamingException e) {
                logger.log(Level.WARNING, e.getMessage(), e);
            }
        }
    }


    private AbstractUserManagerNode createGroupNode(SearchResult sr, AbstractUserManagerNode parent) throws NamingException {
        Group node = (Group) guidMap.get(getGuid(sr));
        if(null == node){
            node = new Group();
            addedNodes.add(node);
        }
        parent.addChild(node);

        /* copy Group attributes */
        node.setName(getStringAttribute(sr, "name"));

        return node;
    }


    private AbstractUserManagerNode createUserNode(SearchResult sr, AbstractUserManagerNode parent) throws NamingException {
        User node = (User) guidMap.get(getGuid(sr));
        if(null == node){
            node = new User();
            addedNodes.add(node);
        }
        parent.addChild(node);

        /* copy User attributes */
        node.setFirstname(getStringAttribute(sr, "givenName"));
        node.setLastname(getStringAttribute(sr, "sn"));
        node.setUsername(getStringAttribute(sr, "uid"));

        return node;
    }

    private AbstractUserManagerNode createOUNode(SearchResult sr, AbstractUserManagerNode parent) throws NamingException {
        OrganisationalUnit node = (OrganisationalUnit) entityUtils.unproxy(guidMap.get(getGuid(sr)));
        if(null == node){
            node = new OrganisationalUnit();
            addedNodes.add(node);
        }
        parent.addChild(node);

        /* copy OU attributes */
        node.setName(getStringAttribute(sr, "name"));

        return node;
    }


    private void postprocessGroups() throws NamingException {

        /* clear */
        for(Entry<LdapName, AbstractUserManagerNode> entry : nodesInDirectoryByName.entrySet()){
            if(entry.getValue() instanceof Group){
                Group group = (Group) entry.getValue();
                group.getUsers().clear();
                group.getOus().clear();
                group.getReferencedGroups().clear();
            }
        }

        /* add appropriate users */
        for(Entry<LdapName, AbstractUserManagerNode> entry : nodesInDirectoryByName.entrySet()){
            if(entry.getValue() instanceof Group){
                Group group = (Group) entry.getValue();
                SearchResult sr = searchResults.get(entry.getKey());
                if(null != sr.getAttributes().get("member")){
                    NamingEnumeration<?> members = sr.getAttributes().get("member").getAll();
                    while(members.hasMore()){
                        LdapName memberName = new LdapName(members.next().toString());
                        AbstractUserManagerNode member = nodesInDirectoryByName.get(memberName);
                        if(null != member){
                            if(member instanceof User)
                                group.addUser((User) member);
                            if(member instanceof OrganisationalUnit)
                                group.addOu((OrganisationalUnit) member);
                            if(member instanceof Group)
                                group.addReferencedGroup((Group) member);
                        }
                    }
                }
            }
        }
    }

    private void printTree(AbstractUserManagerNode current){
        StringBuilder sb = new StringBuilder();
        List<AbstractUserManagerNode> rl = current.getRootLine();
        Collections.reverse(rl);
        for(AbstractUserManagerNode node : rl){
            sb.append(node.getName()).append(".");
        }
        sb.append(current.getName() + " [" + current.getClass().getSimpleName() + "]" );

        if(current instanceof Group){
            Group group = (Group) current;
            sb.append(" (").append(group.getUsers().size() + group.getOus().size() + group.getReferencedGroups().size()).append(" members)");
        }

        System.out.println(sb.toString());

        for(AbstractUserManagerNode cn : current.getChildren()){
            printTree(cn);
        }
    }


    private void deleteRemovedUsers(AbstractUserManagerNode current) {
        for(AbstractUserManagerNode c : current.getChildren()){
            deleteRemovedUsers(c);
        }

        if(null != current.getOrigin() && current.getOrigin().startsWith(providerUrl) && !nodesInDirectoryByGuid.containsKey(current.getGuid())){
            current.getParent().removeChild(current);
            removedNodes.add(current);
        }
    }

    public void run() throws NamingException{
        long start = System.currentTimeMillis();
        createGuidMap(targetNode);

        loadFromDirectory();
        postprocessGroups();

        deleteRemovedUsers(targetNode);
       
        for(AbstractUserManagerNode removedNode : removedNodes){
            userManagerService.remove(removedNode);
        }

        System.out.println("Retrieved nodes from directory: " + nodesInDirectoryByGuid.size() );
        System.out.println("Nodes added: " + addedNodes.size() );
        System.out.println("Nodes removed: " + removedNodes.size() );
        int overallCount = countNodes(targetNode) - 1;
        System.out.println("Overall nodes in rs: " + overallCount);
        System.out.println("Duration: " + (System.currentTimeMillis() - start) + "ms");
        if(overallCount != nodesInDirectoryByGuid.size())
            throw new RuntimeException("Failed to import user data from directory");
        else
            System.out.println("done.");

        //        printTree(targetNode);
    }


    private int countNodes(AbstractUserManagerNode current) {
        int i = 1;
        for(AbstractUserManagerNode n : current.getChildren()){
            i += countNodes(n);
        }
        return i;
    }

}

------------------------------------------

This is the ldapsearch result:-

-----------------------------------------
ldapsearch -H ldap://ipaddrs:port -x -b " ou=people,o=customer1,dc=munidev,dc=org" -D "cn=admin,cn=managers,dc=munidev,dc=org" -w "password" "(objectClass=inetOrgPerson)"
# extended LDIF
#
# LDAPv3
# base < ou=people,o=customer1,dc=munidev,dc=org> with scope subtree
# filter: (objectClass=inetOrgPerson)
# requesting: ALL
#

# John Doe, people, customer1, munidev.org
dn: cn=John Doe,ou=people,o=customer1,dc=munidev,dc=org
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: inetUser
cn: John Doe
givenName: John
sn: Doe
uid: johnd
mail: johndoe@acme.com
userPassword:: e1NTSEF9TThvU0oySjBYM2cyUlNGRkF2WEZHajBlZk5pWEhHYlY4NFYzdEE9PQ=
=
memberOf: cn=staff,ou=groups,o=customer1,dc=munidev,dc=org
memberOf: cn=admins,ou=groups,o=customer1,dc=munidev,dc=org

# Mary Stone, people, customer1, munidev.org
dn: cn=Mary Stone,ou=people,o=customer1,dc=munidev,dc=org
givenName: Mary
sn: Stone
uid: mstone
cn: Mary Stone
mail: mstone@gmail.com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
objectClass: inetUser
userPassword:: e1NTSEF9d2xsSlRDV1lJQWFva2V0WlRUeERsZGlWVlVsQk9KTE4zMzNScFE9PQ=
=
memberOf: cn=accounting,ou=groups,o=customer1,dc=munidev,dc=org

# Test2 User2, people, customer1, munidev.org
dn: cn=Test2 User2,ou=people,o=customer1,dc=munidev,dc=org
cn: Test2 User2
givenName: Test2
mail: test2@acme.com
sn: User2
uid: test2u
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: inetUser
userPassword:: e1NTSEF9NFdaSHh3SzhXbEVERWlOMmhKcWhzYVZGUlNpVG1vREkxUUdnNHc9PQ=
=

# Test3 User3, people, customer1, munidev.org
dn: cn=Test3 User3,ou=people,o=customer1,dc=munidev,dc=org
cn: Test3 User3
givenName: Test3
mail: test3@acme.com
sn: User3
uid: test3u
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: inetUser
userPassword:: e1NTSEF9MzhBc0pvOHVzSGR5ZFhKbkROdWdVZS9VYzBRVHltMTZCN2hucWc9PQ=
=
memberOf: cn=accounting,ou=groups,o=customer1,dc=munidev,dc=org

# Test4 User4, people, customer1, munidev.org
dn: cn=Test4 User4,ou=people,o=customer1,dc=munidev,dc=org
cn: Test4 User4
givenName: Test4
mail: test4@acme.com
sn: User4
uid: test4u
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: inetUser
userPassword:: e1NTSEF9SEM5TXFuNDZGdDN2NDBzNU9XbXZ4MkJsU0lNY2QxOWc3WVJNTVE9PQ=
=

# Test5 User5, people, customer1, munidev.org
dn: cn=Test5 User5,ou=people,o=customer1,dc=munidev,dc=org
cn: Test5 User5
givenName: Test5
mail: test5@acme.com
sn: User5
uid: test5u
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: inetUser
userPassword:: e1NTSEF9SUNuZEhiUHNqVVRTR2dtRVF4ZmkvZ1p0KzRoWVljTnBWaFFlcHc9PQ=
=

# search result
search: 2
result: 0 Success

# numResponses: 7
# numEntries: 6
--------------------------------------




Regards,
Sreejith

Last edited by Sreejith S (2017-03-28 13:19:43)

Offline

#2 2017-03-28 13:23:08

wonky
Member
Registered: 2016-03-01

Re: LDAP Sync to Red Hat Directory Server

Again, this is for RHDS, not default LDAP.

There are some differences in the schema, which will have to be accounted for in the script, which is tailored for the Active Directory schema, so it will fail to find some attributes.

Example: node.setUsername(getStringAttribute(sr, "sAMAccountName"));
samaccountname is the login attribute in active directory, ours is "uid"

Offline

#3 2017-03-28 15:02:34

eduardo
Administrator
Registered: 2016-11-01
Website

Re: LDAP Sync to Red Hat Directory Server

Hi Sreejith & wonky,

your script has some attributes that can not be found in your LDAP server:

1. You don't have a "uidNumber": change it to "uid"
2. You don't have a "name": change it to "sn"
3. Your mapping of users is incorrect, set it to:

if(objectClass.contains("OU")) {
   umNode = createOUNode(sr, parent);
} else if(objectClass.contains("organizationalPerson")) {
   umNode = createUserNode(sr, parent);
} else if(objectClass.contains("GROUP")){
   umNode = createGroupNode(sr, parent);
} else continue;

Here, I changed the person attribute to "organizationalPerson". You must change your OU and GROUP attributes accordingly.

Here the corrected LdapUserLoader:

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.LdapName;

import net.datenwerke.rs.utils.jpa.EntityUtils;
import net.datenwerke.security.service.usermanager.UserManagerService;
import net.datenwerke.security.service.usermanager.entities.AbstractUserManagerNode;
import net.datenwerke.security.service.usermanager.entities.Group;
import net.datenwerke.security.service.usermanager.entities.OrganisationalUnit;
import net.datenwerke.security.service.usermanager.entities.User;




public class LdapUserLoader {
    private final Logger logger = Logger.getLogger(getClass().getName());

    private String ldapBase;
    private String ldapFilter = "(|(objectClass=person)(objectClass=inetUser)(objectClass=organizationalPerson)(objectClass=inetOrgPerson))";
    private String providerUrl;
    private String securityCredentials;
    private String securityPrincipal;
    private OrganisationalUnit targetNode;
    private boolean includeNamespace = false;
    private Map<String, AbstractUserManagerNode> guidMap;
    private Map<LdapName, AbstractUserManagerNode> nodesInDirectoryByName;
    private Map<String, AbstractUserManagerNode> nodesInDirectoryByGuid;
    private TreeMap<LdapName, SearchResult> searchResults;
    private List<AbstractUserManagerNode> removedNodes;
    private List<AbstractUserManagerNode> addedNodes;
    private EntityUtils entityUtils;
    private UserManagerService userManagerService;
    private class AdGUID {
        byte[] bytes;
        public AdGUID(byte[] bytes) {
            this.bytes = bytes;
        }
        private void addByte(StringBuffer sb, int k) {
            if(k<=0xF)
                sb.append("0");
            sb.append(Integer.toHexString(k));
        }
        @Override
        public String toString() {
            StringBuffer sb = new StringBuffer();
            addByte(sb, (int)bytes[3] & 0xFF);
            addByte(sb, (int)bytes[2] & 0xFF);
            addByte(sb, (int)bytes[1] & 0xFF);
            addByte(sb, (int)bytes[0] & 0xFF);
            sb.append("-");
            addByte(sb, (int)bytes[5] & 0xFF);
            addByte(sb, (int)bytes[4] & 0xFF);
            sb.append("-");
            addByte(sb, (int)bytes[7] & 0xFF);
            addByte(sb, (int)bytes[6] & 0xFF);
            sb.append("-");
            addByte(sb, (int)bytes[8] & 0xFF);
            addByte(sb, (int)bytes[9] & 0xFF);
            sb.append("-");
            addByte(sb, (int)bytes[10] & 0xFF);
            addByte(sb, (int)bytes[11] & 0xFF);
            addByte(sb, (int)bytes[12] & 0xFF);
            addByte(sb, (int)bytes[13] & 0xFF);
            addByte(sb, (int)bytes[14] & 0xFF);
            addByte(sb, (int)bytes[15] & 0xFF);
            return sb.toString();
        }
    }
    public LdapUserLoader(EntityUtils entityUtils, UserManagerService userManagerService) {
        this.entityUtils = entityUtils;
        this.userManagerService = userManagerService;
    }

    public String getLdapBase() {
        return ldapBase;
    }
    public String getProviderUrl() {
        return providerUrl;
    }
    public String getSecurityCredentials() {
        return securityCredentials;
    }
    public String getSecurityPrincipal() {
        return securityPrincipal;
    }
    public void setLdapBase(String ldapBase) {
        this.ldapBase = ldapBase;
    }
    public void setProviderUrl(String providerUrl) {
        this.providerUrl = providerUrl;
    }
    public void setSecurityCredentials(String securityCredentials) {
        this.securityCredentials = securityCredentials;
    }
    public void setSecurityPrincipal(String securityPrincipal) {
        this.securityPrincipal = securityPrincipal;
    }
    public void setTargetNode(OrganisationalUnit targetNode) {
        this.targetNode = targetNode;
    }
    public boolean isIncludeNamespace() {
        return includeNamespace;
    }
    public void setIncludeNamespace(boolean includeNamespace) {
        this.includeNamespace = includeNamespace;
    }
    public String getLdapFilter() {
        return ldapFilter;
    }
    public void setLdapFilter(String ldapFilter) {
        this.ldapFilter = ldapFilter;
    }
  
    private Properties compileProperties(){
        Properties props = new Properties();
        props.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        props.setProperty(Context.PROVIDER_URL, providerUrl);
        props.setProperty(Context.URL_PKG_PREFIXES, "com.sun.jndi.url");
        props.setProperty(Context.REFERRAL, "throw");
        props.setProperty(Context.SECURITY_AUTHENTICATION, "simple");
        props.setProperty(Context.SECURITY_PRINCIPAL, securityPrincipal);
        props.setProperty(Context.SECURITY_CREDENTIALS, securityCredentials);
        /* return these as binary */
        props.put("java.naming.ldap.attributes.binary","objectGUID");
        return props;
    }
    private void createGuidMap(AbstractUserManagerNode current) {
        Map<String, AbstractUserManagerNode> map = new HashMap<>();
        createGuidMap(current, map );
        guidMap = map;
    }
    private void createGuidMap(AbstractUserManagerNode current, Map<String, AbstractUserManagerNode> map){
        map.put(current.getGuid(), (AbstractUserManagerNode)entityUtils.unproxy(current));
        for(AbstractUserManagerNode cn : current.getChildren()){
            createGuidMap(cn, map);
        }
    }
    private String getStringAttribute(SearchResult sr, String attributeName) throws NamingException{
        try{
            return sr.getAttributes().get(attributeName).get().toString();
        }catch(Exception e){
            logger.log(Level.WARNING,"failed to retrieve attribute '" + attributeName + "' from " + sr.getNameInNamespace(), e);
            return null;
        }
    }
   private String getGuid(SearchResult sr) throws NamingException{
    try{
        return sr.getAttributes().get("uid").get().toString();
    }catch(Exception e){
        throw new RuntimeException("failed to retrieve objectGUID from " + sr.getNameInNamespace(), e);
    }
}
    private void loadFromDirectory() throws NamingException {
        Properties props = compileProperties();
        String originBase = this.providerUrl.endsWith("/")?providerUrl:providerUrl + "/";
        this.nodesInDirectoryByName = new HashMap<>();
        this.nodesInDirectoryByGuid = new HashMap<>();
        this.addedNodes = new ArrayList<>();
        this.removedNodes = new ArrayList<>();
        DirContext ctx = null ;
        try {
            ctx = new InitialDirContext(props);
            SearchControls searchControls = new SearchControls();
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
            LdapName ldapBaseName = new LdapName(getLdapBase());
            NamingEnumeration<SearchResult> results = ctx.search(ldapBaseName, this.ldapFilter, searchControls);
            /* order search results by name to make sure children never get processed before their parent */
            searchResults = new TreeMap<>();
            while (results.hasMoreElements()) {
                SearchResult sr = (SearchResult) results.next();
                searchResults.put(new LdapName(sr.getNameInNamespace()), sr);
            }
            for(SearchResult sr : searchResults.values()){
                try {
                    LdapName nodeName = new LdapName(isIncludeNamespace() ? sr.getNameInNamespace() : sr.getName());
                    LdapName nodeNameInNamespace = new LdapName(sr.getNameInNamespace());
                    /* skip empty nodes */
                    if(nodeName.size() == 0)
                        continue;

                    /* get parent node */
                    LdapName parentName = (LdapName) nodeNameInNamespace.getPrefix(Math.max(0, nodeNameInNamespace.size() - 1));
                    AbstractUserManagerNode parent = this.nodesInDirectoryByName.get(parentName);
                    if(null == parent){
                        if(parentName.equals(new LdapName(ldapBase))){
                            /* root node */
                            parent = targetNode;
                        }else{
                            throw new IllegalStateException("Missing parent for " + sr.getNameInNamespace());
                        }
                    }
                    /* create node */
                    Attribute objectClass = sr.getAttributes().get("objectClass");
                    AbstractUserManagerNode umNode = null;
                    if(objectClass.contains("OU")) {
                        umNode = createOUNode(sr, parent);
                    } else if(objectClass.contains("organizationalPerson")) {
                        umNode = createUserNode(sr, parent);
                    } else if(objectClass.contains("GROUP")){
                        umNode = createGroupNode(sr, parent);
                    } else continue;
                    /* set common attributes */
                    umNode.setWriteProtection(false);
                    umNode.setGuid(getGuid(sr));
                    umNode.setOrigin(originBase + sr.getNameInNamespace());
                    nodesInDirectoryByName.put(new LdapName(sr.getNameInNamespace()), umNode);
                    nodesInDirectoryByGuid.put(getGuid(sr), umNode);
                }catch(Exception e){
                    throw new RuntimeException("Error processing search result: " + sr.getNameInNamespace() , e);
                }
            }

        }finally{
            try {
                if(null != ctx)
                    ctx.close();
            } catch (NamingException e) {
                logger.log(Level.WARNING, e.getMessage(), e);
            }
        }
    }

    private AbstractUserManagerNode createGroupNode(SearchResult sr, AbstractUserManagerNode parent) throws NamingException {
        Group node = (Group) guidMap.get(getGuid(sr));
        if(null == node){
            node = new Group();
            addedNodes.add(node);
        }
        parent.addChild(node);
        /* copy Group attributes */
        node.setName(getStringAttribute(sr, "name"));
        return node;
    }

    private AbstractUserManagerNode createUserNode(SearchResult sr, AbstractUserManagerNode parent) throws NamingException {
        User node = (User) guidMap.get(getGuid(sr));
        if(null == node){
            node = new User();
            addedNodes.add(node);
        }
        parent.addChild(node);
        /* copy User attributes */
        node.setFirstname(getStringAttribute(sr, "givenName"));
        node.setLastname(getStringAttribute(sr, "sn"));
        node.setUsername(getStringAttribute(sr, "uid"));
        return node;
    }
    private AbstractUserManagerNode createOUNode(SearchResult sr, AbstractUserManagerNode parent) throws NamingException {
        OrganisationalUnit node = (OrganisationalUnit) entityUtils.unproxy(guidMap.get(getGuid(sr)));
        if(null == node){
            node = new OrganisationalUnit();
            addedNodes.add(node);
        }
        parent.addChild(node);
        /* copy OU attributes */
        node.setName(getStringAttribute(sr, "sn"));
        return node;
    }

    private void postprocessGroups() throws NamingException {
        /* clear */
        for(Entry<LdapName, AbstractUserManagerNode> entry : nodesInDirectoryByName.entrySet()){
            if(entry.getValue() instanceof Group){
                Group group = (Group) entry.getValue();
                group.getUsers().clear();
                group.getOus().clear();
                group.getReferencedGroups().clear();
            }
        }
        /* add appropriate users */
        for(Entry<LdapName, AbstractUserManagerNode> entry : nodesInDirectoryByName.entrySet()){
            if(entry.getValue() instanceof Group){
                Group group = (Group) entry.getValue();
                SearchResult sr = searchResults.get(entry.getKey());
                if(null != sr.getAttributes().get("member")){
                    NamingEnumeration<?> members = sr.getAttributes().get("member").getAll();
                    while(members.hasMore()){
                        LdapName memberName = new LdapName(members.next().toString());
                        AbstractUserManagerNode member = nodesInDirectoryByName.get(memberName);
                        if(null != member){
                            if(member instanceof User)
                                group.addUser((User) member);
                            if(member instanceof OrganisationalUnit)
                                group.addOu((OrganisationalUnit) member);
                            if(member instanceof Group)
                                group.addReferencedGroup((Group) member);
                        }
                    }
                }
            }
        }
    }
    private void printTree(AbstractUserManagerNode current){
        StringBuilder sb = new StringBuilder();
        List<AbstractUserManagerNode> rl = current.getRootLine();
        Collections.reverse(rl);
        for(AbstractUserManagerNode node : rl){
            sb.append(node.getName()).append(".");
        }
        sb.append(current.getName() + " [" + current.getClass().getSimpleName() + "]" );
        if(current instanceof Group){
            Group group = (Group) current;
            sb.append(" (").append(group.getUsers().size() + group.getOus().size() + group.getReferencedGroups().size()).append(" members)");
        }
        System.out.println(sb.toString());
        for(AbstractUserManagerNode cn : current.getChildren()){
            printTree(cn);
        }
    }

    private void deleteRemovedUsers(AbstractUserManagerNode current) {
        for(AbstractUserManagerNode c : current.getChildren()){
            deleteRemovedUsers(c);
        }
        if(null != current.getOrigin() && current.getOrigin().startsWith(providerUrl) && !nodesInDirectoryByGuid.containsKey(current.getGuid())){
            current.getParent().removeChild(current);
            removedNodes.add(current);
        }
    }
    public void run() throws NamingException{
        long start = System.currentTimeMillis();
        createGuidMap(targetNode);
        loadFromDirectory();
        postprocessGroups();
        deleteRemovedUsers(targetNode);
        
        for(AbstractUserManagerNode removedNode : removedNodes){
            userManagerService.remove(removedNode);
        }
        System.out.println("Retrieved nodes from directory: " + nodesInDirectoryByGuid.size() );
        System.out.println("Nodes added: " + addedNodes.size() );
        System.out.println("Nodes removed: " + removedNodes.size() );
        int overallCount = countNodes(targetNode) - 1;
        System.out.println("Overall nodes in rs: " + overallCount);
        System.out.println("Duration: " + (System.currentTimeMillis() - start) + "ms");
        if(overallCount != nodesInDirectoryByGuid.size())
            throw new RuntimeException("Failed to import user data from directory");
        else
            System.out.println("done.");
        //        printTree(targetNode);
    }

    private int countNodes(AbstractUserManagerNode current) {
        int i = 1;
        for(AbstractUserManagerNode n : current.getChildren()){
            i += countNodes(n);
        }
        return i;
    }
}

Cheers,
Eduardo

Offline

#4 2017-03-28 16:04:01

Sreejith S
Member
Registered: 2016-11-16

Re: LDAP Sync to Red Hat Directory Server

Hi Eduardo,

Thanks a lot for your help. We are able to get sync the users now.

Regards,
Sreejith

Offline

#5 2017-03-30 12:57:46

Sreejith S
Member
Registered: 2016-11-16

Re: LDAP Sync to Red Hat Directory Server

Hi Eduardo,

Now we are having another doubt that, actually we are hard-coding the Organisation name in this script ie   

lul.setLdapBase("ou=people,o=customer1,dc=munidev,dc=org"); 

Instead of that can we get the 'o' from the URL.

For example if we are executing the url 'abc.reportserver.com' ,then we need to get the 'abc' as the 'o' in the ldapimport script. Or else is there any way to get the complete url in the script or just the first part.

Regards,
Sreejith

Offline

#6 2017-03-30 13:27:45

eduardo
Administrator
Registered: 2016-11-01
Website

Re: LDAP Sync to Red Hat Directory Server

Hi Sreejith,

You can access the HttpServletRequest URL if available by:

import javax.servlet.http.HttpServletRequest

HttpServletRequest req = GLOBALS.getInstance(HttpServletRequest.class)

return "URL: " + req.getRequestURL();

You can also access to the parameters using req.getParameter("abc");
More information on HttpServletRequest here: https://tomcat.apache.org/tomcat-7.0-do … quest.html

Cheers,
Eduardo

Offline

#7 2017-03-30 13:34:00

eduardo
Administrator
Registered: 2016-11-01
Website

Re: LDAP Sync to Red Hat Directory Server

Further, if executing a script via URL you have access to the predefined variable httpRequest as well as httpResponse which provide access to the HTTP request and response object.

Offline

Board footer

Powered by FluxBB