LdapHelper.java

package com.mycim.webapp.utils;

import com.mycim.framework.logging.Logger;
import com.mycim.framework.logging.LoggerFactory;
import com.mycim.framework.utils.lang.StringUtils;
import com.mycim.framework.utils.lang.collections.MapUtils;
import com.mycim.framework.utils.msg.JsonUtils;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.*;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import java.util.*;

public class LdapHelper {

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

    @SuppressWarnings(value = "unchecked")
    public static LdapContext getCtx(Map<String, Object> ldapInfo) throws NamingException {
        //String authenticationType = MapUtils.getString(ldapInfo, "authenticationType");
        String principalSuffix = MapUtils.getString(ldapInfo, "principalSuffix");
        String providerUrl = MapUtils.getString(ldapInfo, "providerUrl");
        String baseDn = MapUtils.getString(ldapInfo, "baseDn");
        String factoryInitial = MapUtils.getString(ldapInfo, "factoryInitial");
        String securityAuthentication = MapUtils.getString(ldapInfo, "securityAuthentication");
        String securityPrincipal = MapUtils.getString(ldapInfo, "securityPrincipal");
        String securityCredentials = MapUtils.getString(ldapInfo, "securityCredentials");
        Long timeOut = MapUtils.getLongValue(ldapInfo, "timeOut", 3000L);


        Hashtable<String, String> env = new Hashtable<String, String>();
        //记录工JNDI工厂
        env.put(Context.INITIAL_CONTEXT_FACTORY, factoryInitial);//com.sun.jndi.ldap.LdapCtxFactory
        //LDAP的地址,要根据LDAP服务器IP进行修改,389是LDAP的默认端口
        env.put(Context.PROVIDER_URL, providerUrl + baseDn);//ldap://10.182.136.11:389/DC=nsemii,DC=com
        //默认授权类型,一般不用改
        env.put(Context.SECURITY_AUTHENTICATION, securityAuthentication);//simple
        //LDAP的账户名,一般是这样的格式:dc=hisi,dc=huawei,dc=com
        env.put(Context.SECURITY_PRINCIPAL, securityPrincipal);//FA_ReportAdmin@nsemii.com
        //密码
        env.put(Context.SECURITY_CREDENTIALS, securityCredentials);//FAA411faa

        env.put("com.sun.jndi.ldap.connect.timeout", timeOut.toString());
        env.put("com.sun.jndi.ldap.read.timeout", timeOut.toString());
        // 链接ldap
        LdapContext ctx = new InitialLdapContext(env, null);
        logger.info("LDAP认证服务连接成功....");
        return ctx;
    }

    public static String authenticate(String usr, String pwd, Map<String, Object> ldapInfo) {
        String principalSuffix = MapUtils.getString(ldapInfo, "principalSuffix");
        LdapContext ctx = null;
        try {
            ctx = getCtx(ldapInfo);
        } catch (NamingException e1) {
            logger.error(e1);
            return "Ldap Server connect error!";
        }
        try {
            ctx.addToEnvironment(Context.SECURITY_PRINCIPAL, usr + principalSuffix);
            ctx.addToEnvironment(Context.SECURITY_CREDENTIALS, pwd);
            ctx.reconnect(null);
            return "";
        } catch (NamingException e) {
            logger.error(e);
            return "Ldap login authenticate error!";
        } finally {
            closeCtx(ctx);
        }
    }

    public static List<Object> getUserKey(String usr, Map<String, Object> ldapInfo) throws Exception {
        logger.info("****---> 需要查询的ad信息:{}", usr);
        ArrayList<Object> resultList = new ArrayList<>();
        LdapContext ldapContext = getCtx(ldapInfo);

        if (ldapContext != null) {
            String company = "";
            String result = "";
            try {
                // 域节点
                String searchBase = MapUtils.getString(ldapInfo, "searchDn");
                // cn=*name*模糊查询     cn=name 精确查询
                String searchFilter = "(objectclass=user)";
                // 创建搜索控制器
                SearchControls searchCtls = new SearchControls();
                String returnedAtts[] = {"sAMAccountName", "cn", "givenName", "sn", "displayName", "mail", "entryUUID"};
                searchCtls.setReturningAttributes(returnedAtts); //设置指定返回的字段,不设置则返回全部
                //  设置搜索范围 深度
                searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
                // 根据设置的域节点、过滤器类和搜索控制器搜索LDAP得到结果
                NamingEnumeration answer = ldapContext.search(searchBase, searchFilter, searchCtls);
                // 初始化搜索结果数为0
                int totalResults = 0;
                int rows = 0;
                while (answer.hasMoreElements()) {
                    ++rows;
                    // 得到符合搜索条件的DN
                    SearchResult sr = (SearchResult) answer.next();
                    String dn = sr.getName();
                    logger.info("****---> DN: " + dn);
                    //符合条件的属性集
                    Attributes Attrs = sr.getAttributes();
                    logger.info("***--->>>Attributes: " + JsonUtils.toString(Attrs));
                    if (Attrs != null) {
                        try {
                            for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore(); ) {
                                Attribute Attr = (Attribute) ne.next();
                                logger.info("***--->>>Attribute: " + JsonUtils.toString(Attr));
                                // 读取属性值
                                for (NamingEnumeration e = Attr.getAll(); e.hasMore(); totalResults++) {
                                    company = e.next().toString();
                                    Map<String, Object> tempJson = new HashMap<>();
                                    tempJson.put(Attr.getID(), company.toString());
                                    resultList.add(tempJson);
                                }
                            }
                        } catch (NamingException e) {
                            logger.info("****---> Throw Exception : " + e.getMessage());
                        }
                    }
                }
                logger.info("****---> 总共用户数:" + rows);
            } catch (NamingException e) {
                logger.error("****---> Throw Exception : " + e.getMessage());
            } finally {
                try {
                    ldapContext.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        logger.info("***--->>>getUserKey返回的结果: " + JsonUtils.toString(resultList));
        return resultList;
    }

    public static Map searchUserInfo(String usr, Map<String, Object> ldapInfo) throws Exception {
        Map resultMap = new HashMap();
        LdapContext ctx = getCtx(ldapInfo);
        String result = "";
        String baseDn = MapUtils.getString(ldapInfo, "searchDn");
        SearchControls constraints = new SearchControls();
        constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
        NamingEnumeration<?> en = ctx.search(baseDn, "sAMAccountName=" + usr, constraints);
        if (en == null) {
            result += "Have no NamingEnumeration. \n";
            resultMap.put("msg", result);

        }
        if (!en.hasMoreElements()) {
            result += "Have no element. \n";
            resultMap.put("msg", result);
        }
        while (en != null && en.hasMoreElements()) {
            Object obj = en.nextElement();
            if (obj instanceof SearchResult) {
                SearchResult sr = (SearchResult) obj;
                Attributes attrs = sr.getAttributes();
                String sn = attrs.get("sn") + "";
                String givenName = attrs.get("givenName") + "";
                String mail = attrs.get("mail") + "";
                String localName =
                        sn.substring(sn.indexOf(":") + 1).trim() + givenName.substring(givenName.indexOf(":")).trim();
                resultMap.put("mail", mail.substring(mail.indexOf(":") + 1).trim());
                resultMap.put("localName", localName);
            } else {
                logger.info(obj);
            }
        }
        return resultMap;
    }


    /**
     * @param ldappath 本级条目路径,如:dc=cs,dc=hunan,dc=com
     * @param attrname 用于过滤的属性名,即条目包含该属性,可为空串
     * @param attrval  用于过滤的属性值,即上面的属性包含该属性值,可为空串
     *                 <p>
     *                 注意,当attrname为空串时,将忽略attrval 这个函数会返回NamingEnumeration对象,通过这个对象,我们可以遍历出所有搜索到的结果
     * @return
     */
    public static NamingEnumeration<Object> searchSubEntry(DirContext ctx, String ldappath, String attrname,
                                                           String attrval) {
        NamingEnumeration ret = null;
        if (ctx != null) {
            try {
                //先判断一下这个条目是不是存在
                if (isExist(ctx, ldappath)) {
                    logger.info("***>>>目录存在,开始搜索");
                    //设定搜索条件    建一个属性集合对象
                    Attributes matchAttrs = new BasicAttributes(true);
                    //如果传入了属性名称条件就加到属性集合里
                    if (StringUtils.isNotBlank(attrname)) {
                        logger.info("***>>>添加了过滤属性名称{}", attrname);
                        matchAttrs.put(new BasicAttribute(attrname, attrval));
                    }
                    //搜索符合条件的结果
                    NamingEnumeration answer = ctx.search(ldappath, matchAttrs);
                    logger.info("***>>>搜索到的符合条件的结果: ", JsonUtils.toString(answer));
                    ret = answer;
                }
                logger.info("***>>>{}目录不存在", ldappath);
            } catch (NamingException ex) {
                ret = null;   //出现异常时会返回null
                logger.error(ex);
            }
        }
        return ret;
    }


    public static boolean isExist(DirContext ldapCtx, String ldappath) {
        try {
            ldapCtx.search(ldappath, null);  //测试检索一下
            return true;                         //表示这个条目是存在的
        } catch (NamingException ex) {
            return false;
        }
    }


    public static void closeCtx(LdapContext ctx) {
        try {
            ctx.close();
        } catch (NamingException ex) {
            logger.error(ex);
        }
    }

}