org.jkcsoft.java.util.JndiHelper.java Source code

Java tutorial

Introduction

Here is the source code for org.jkcsoft.java.util.JndiHelper.java

Source

/*
 * Copyright (c) Jim Coles (jameskcoles@gmail.com) 2018 through present.
 *
 * Licensed under the following license agreement:
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Also see the LICENSE file in the repository root directory.
 */
package org.jkcsoft.java.util;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.logging.Log;
import org.jkcsoft.java.systems.components.Constants;
import org.jkcsoft.java.systems.contexts.BehavioralContext;

import javax.naming.*;
import javax.naming.directory.*;
import java.util.*;

/**
 * @author Jim Coles
 * @version 1.0
 */
public class JndiHelper {

    //----------------------------------------------------------------------------
    // Constants
    //----------------------------------------------------------------------------
    public static final String LDAP_DC = "dc";
    public static final String LDAP_DISTINGUISHEDNAME = "distinguishedName";
    public static final String LDAP_USER_LASTNAME = "sn";
    public static final String LDAP_USER_GIVENNAME = "givenName";
    public static final String LDAP_USER_SAMACCOUNTNAME = "sAMAccountName";
    public static final String LDAP_USER_DISPLAYNAME = "displayName";
    public static final String LDAP_USER_MAIL = "mail";
    //
    public static final String KEY_JNDI_CONN = "jndi-connection";
    public static final String KEY_JNDI_CONN_HOST = KEY_JNDI_CONN + "." + "host";
    public static final String KEY_JNDI_CONN_PORT = KEY_JNDI_CONN + "." + "port";
    public static final String KEY_JNDI_CONN_MODE = KEY_JNDI_CONN + "." + "mode";

    //----------------------------------------------------------------------------
    // Static members
    //----------------------------------------------------------------------------
    private static Log log = LogHelper.getLogger(JndiHelper.class);

    public static Context getContextFromProps(Configuration config) throws Exception {
        String url = getJndiUrlFromProps(config);

        return getContext(url, ""); // TODO: get icf class name from config..
    }

    public static String getJndiUrlFromProps(Configuration config) throws IllegalArgumentException {
        String scheme = config.getString(KEY_JNDI_CONN_MODE, "tcp");
        String host = config.getString(KEY_JNDI_CONN_HOST, "localhost");
        String port = "";

        if (scheme.equals("tcp") || scheme.equals("tcps")) {
            port = config.getString(KEY_JNDI_CONN_PORT, "3035");
        } else if (scheme.equals("http")) {
            throw new IllegalArgumentException("http jndi connection not supported");
        } else if (scheme.equals("https")) {
            throw new IllegalArgumentException("https jndi connection not supported");
        } else if (scheme.equals("rmi")) {
            port = config.getString(KEY_JNDI_CONN_PORT, "1099");
        }

        String name = "";
        if (scheme.equals("rmi")) {
            name = config.getString("jndiname", "");
        }

        String url = scheme + "://" + host + ":" + port + "/" + name;
        return url;
    }

    public static Context getJmsContext(String url) throws NamingException {
        return getContext(url, ""); // TODO: get icf name from config...
    }

    public static Context getContext(String url, String contextFactoryName) throws NamingException {
        log.debug("Getting initial context from jndi url [" + url + "]");
        Context ctx = null;
        Hashtable properties = new Hashtable();
        properties.put(Context.INITIAL_CONTEXT_FACTORY, contextFactoryName);

        properties.put(Context.PROVIDER_URL, url);

        try {
            // Creating the JNDI directory context (with LDAP context
            // factory), performs an LDAP bind to the LDAP provider thereby
            // authenticating the username/pw.
            ctx = new InitialContext(properties);
        } catch (NamingException ex) {
            throw ex;
        }

        return ctx;
    }

    public static Map getUserInfo(BehavioralContext ctx, String userName) throws NamingException {
        Map infoMap = null;

        Configuration cfg = ctx.getConfig();
        // 
        String searchRelativeDc = cfg.getString(Constants.KEY_AD_USER_NODE_DN);
        String theFilter = LDAP_USER_SAMACCOUNTNAME + "=" + userName;
        List theAttrsList = new Vector(Arrays.asList(ldapUserAttrs));
        theAttrsList.addAll(Arrays.asList(ldapTopAttrs));

        int countLimit = 1000;
        int timeLimitMillis = 30000;
        boolean returnObject = false;
        boolean derefObj = true;

        SearchControls scs = new SearchControls(SearchControls.SUBTREE_SCOPE, countLimit, timeLimitMillis,
                (String[]) theAttrsList.toArray(new String[0]), returnObject, derefObj);

        DirContext rootCtx = getTsessAccountContext(ctx);

        try {
            log.debug("Search params name[" + searchRelativeDc + "] " + "filter[" + theFilter + "] controls[" + scs
                    + "]");

            NamingEnumeration results = rootCtx.search(searchRelativeDc, theFilter, scs);

            if (results == null || !results.hasMore())
                throw new NamingException("User LDAP entry not found");

            SearchResult searchResult = ((SearchResult) results.next());
            if (searchResult == null)
                throw new NamingException("User LDAP entry not found");

            if (log.isTraceEnabled()) {
                logLdap(log, 0, 0, searchResult);
            }

            Attributes userLdapAttrs = searchResult.getAttributes();
            infoMap = new HashMap();
            for (Iterator attrIter = theAttrsList.iterator(); attrIter.hasNext();) {
                loadMap(infoMap, userLdapAttrs, (String) attrIter.next());
            }
        } finally {
            safeClose(rootCtx);
        }

        return infoMap;
    }

    private static void loadMap(Map info, Attributes userLdapAttrs, String key) throws NamingException {
        Attribute attribute = userLdapAttrs.get(key);
        Object value = null;
        if (attribute != null) {
            value = attribute.get().toString();
        } else {
            log.warn("Null value of AD param [" + key + "]");
        }
        info.put(key, value);
    }

    public static DirContext getTsessAccountContext(BehavioralContext bctx) throws NamingException {
        Configuration cfg = bctx.getConfig();
        return getDirContext(bctx, cfg.getString(Constants.KEY_AD_SERVICE_USER_NAME),
                cfg.getString(Constants.KEY_AD_SERVICE_USER_PW));
    }

    public static DirContext getDirContext(BehavioralContext bctx, Object principal, Object credentials)
            throws NamingException {
        DirContext ctx = null;

        Configuration tconfig = bctx.getConfig();
        String ldapProvider = "ldap" + "://" + tconfig.getString(Constants.KEY_AD_HOST) + ":"
                + tconfig.getString(Constants.KEY_AD_PORT) + "/" + tconfig.getString(Constants.KEY_AD_ROOT_DN);

        log.info("Using LDAP url: [" + ldapProvider + "]");

        //        String url, String contextFactoryName,

        Hashtable jndiEnv = new Hashtable();

        jndiEnv.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        jndiEnv.put(Context.PROVIDER_URL, ldapProvider);
        jndiEnv.put(Context.REFERRAL, "follow");

        if (tconfig.getBoolean(Constants.KEY_AD_SSL)) {
            log.info("Using SSL for LDAP");
            jndiEnv.put(Context.SECURITY_PROTOCOL, "ssl");
        }
        jndiEnv.put(Context.SECURITY_AUTHENTICATION, "simple");

        if (principal != null)
            jndiEnv.put(Context.SECURITY_PRINCIPAL, principal);

        if (credentials != null)
            jndiEnv.put(Context.SECURITY_CREDENTIALS, credentials);

        try {
            // Creating the JNDI directory context (with LDAP context
            // factory), performs an LDAP bind to the LDAP provider thereby
            // authenticating the username/pw.
            ctx = new InitialDirContext(jndiEnv);
        } catch (NamingException ex) {
            log.error("Directory context init failed", ex);
            throw ex;
        }

        return ctx;
    }

    public static void safeClose(Context context) {
        if (context != null) {
            try {
                context.close();
            } catch (NamingException e) {
                log.error("safeClose()", e);
            }
        } else {

        }
    }

    public static Object lookup(Context jndi, String name) throws NamingException {
        //        String l_name = cleanName(p_name);

        Object retObj = jndi.lookup(name);

        if (log.isDebugEnabled()) {
            try {
                StringBuilder sbLog = new StringBuilder();

                NameParser parser = jndi.getNameParser(name);
                Name jndiName = parser.parse(name);
                List lNames = Collections.list(jndiName.getAll());
                if (lNames != null) {
                    Iterator iNames = lNames.iterator();
                    while (iNames.hasNext()) {
                        String elemName = (String) iNames.next();
                        Strings.appendLine(sbLog, "name [" + elemName + "]");
                    }
                }
                log.debug("Jndi parse of [" + name + "] => " + sbLog);
            } catch (NamingException e) {
                log.warn("Error in getting JNDI name info", e);
            }
        }

        return retObj;
    }

    private static CharReplacer dnsToJndi = new CharReplacer(new String[][] { { ".", "_" } });
    private static final String ldapTopAttrs[] = new String[] { LDAP_DISTINGUISHEDNAME, LDAP_DC };
    private static final String ldapUserAttrs[] = new String[] { LDAP_USER_MAIL, LDAP_USER_DISPLAYNAME,
            LDAP_USER_SAMACCOUNTNAME, LDAP_USER_GIVENNAME, LDAP_USER_LASTNAME };

    public static String cleanName(String inName) {
        //        return dnsToJndi.replace(inName);
        return Strings.replaceAll(inName, ".", "_");
    }

    public static void logLdap(Log plog, int level, int nth, Object dirEntry) throws NamingException {
        try {
            if (dirEntry instanceof NamingEnumeration) {
                NamingEnumeration nameEnum = (NamingEnumeration) dirEntry;
                JndiHelper.logLevel(plog, level, nth, "Naming Enumeration: " + nameEnum);
                try {
                    int nthThis = 0;
                    List nameList = new Vector(Collections.list(nameEnum));
                    Collections.sort(nameList, new Comparator() {
                        public int compare(Object o1, Object o2) {
                            if (o1 instanceof Attribute) {
                                return String.CASE_INSENSITIVE_ORDER.compare(((Attribute) o1).getID(),
                                        ((Attribute) o2).getID());
                            }
                            return 0;
                        }
                    });
                    Iterator nameIter = nameList.iterator();
                    while (nameIter.hasNext()) {
                        logLdap(plog, level + 1, nthThis++, nameIter.next());
                    }
                } catch (NamingException ex) {
                    plog.error("Exception iterating thru NamingEnumeration: " + ex.getMessage());
                }
            } else if (dirEntry instanceof Attribute) {
                Attribute dirAttr = (Attribute) dirEntry;
                JndiHelper.logLevel(plog, level, nth, "Attribute: [" + dirAttr + "]");
            } else if (dirEntry instanceof DirContext) {
                DirContext lctx = (DirContext) dirEntry;
                JndiHelper.logLevel(plog, level, nth,
                        "LDAP Context: DN [" + lctx.getNameInNamespace() + "]" + " Attributes ==>");
                logLdap(plog, level, nth, lctx.getAttributes("").getAll());
            } else if (dirEntry instanceof SearchResult) {
                SearchResult sr = (SearchResult) dirEntry;
                JndiHelper.logLevel(plog, level, nth, "SearchResult: ClassName of Bound Object ["
                        + sr.getClassName() + "]" + " Name: [" + sr.getName() + "]" + " Bound Object ==>");
                //                sr.s
                logLdap(plog, level, nth, sr.getObject());
                logLdap(plog, level, nth, sr.getAttributes().getAll());
            } else {
                JndiHelper.logLevel(plog, level, nth, "(?) class of entry: [" + dirEntry + "]");
            }
            nth++;
        } catch (NamingException e1) {
            plog.error("Naming Exception (will try to continue): " + e1.getMessage());
        }
    }

    public static void logLevel(Log plog, int level, int nth, String msg) {
        plog.info(Strings.multiplyString("\t", level) + "Dir Entry [" + nth + "]: " + msg);
    }

    //----------------------------------------------------------------------------
    // Private instance vars
    //----------------------------------------------------------------------------

    //----------------------------------------------------------------------------
    // Constructor(s)
    //----------------------------------------------------------------------------

    //----------------------------------------------------------------------------
    // Instance methods
    //----------------------------------------------------------------------------

}