锁定老帖子 主题:通过ldap搜索未知结构的AD
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-09-23
最后修改:2011-09-23
网上通过ldap操作AD的例子很多,我也是通过网络搜索然后成功的搜索了公司未知结构的AD,中间经历了一些波折,下面总结一下过程,我相信对需要操作AD的码工码农们多多少少是有些帮助。 1 获取DirContext要注意的地方。 以下是构造DirContext的基本代码:
DirContext ctx = null; String ldapURL = "ldap://10.0.15.1:389"; String user = "test@xxx.com"; String password = "you password"; Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.PROVIDER_URL, ldapURL); env.put(Context.SECURITY_PRINCIPAL, user); env.put(Context.SECURITY_CREDENTIALS, password); ctx = new InitialDirContext(env);
(1) 对AD结构是未知的情况下,ldapURL的写法保守一点比较好,所以不在端口后加DN。 (2) 为什么不用域名,而用IP,因为有时候通过域名访问不到AD,存在不稳定情况,获取域地址方法,通过cmd输入ipconfig -all找到win server既是所需ip,可能会存在多个,一般大点的公司会有多个域控制器。 (3)用户名的写法,不能直接用用户名,而要加上域信息,如userid@domain address或domain address\userid方式,如test@xxx.com,test是域帐号,xxx.com为AD域名,否则会报异常。
2 查询要注意的地方。 因为AD结构未知,所以查询仍然要保守点。
DirContext cnt = null; try { cnt = this.getContext(); String base = "dc=xxx,dc=com"; String filter = "(&(objectClass=user)(sAMAccountName=*test*))"; int limitsize = 1; SearchControls searchCons = new SearchControls(); NamingEnumeration namingEnum = null; searchCons.setSearchScope(2); searchCons.setCountLimit(limitsize); searchCons.setTimeLimit(0); namingEnum = cnt.search(base, filter, searchCons); print(namingEnum, base, limitsize); } catch (Exception e) { e.printStackTrace(); } finally { if (cnt != null) { cnt.close(); } }
(1) 未知AD情况下base开始只写出dc,因为域帐号通常不会直接建立在user节点下,一般会自己建立组织。 (2) 过滤器条件越少越好,而且最好用模糊匹配,如String filter = sAMAccountName=*test*",其中test为登录帐号名。 (4) searchCons.setTimeLimit(0),设超时时间为0标识没有超时限制。 (5)因为过滤条件比较简单而且是模糊条件,此时基本上能查出想要的数据,但节点数量很大的话查询会比较慢,此时可以根据查询的结果信息来补充DN和filter,如在DN中加入OU根,在filter加上多个条件,filter加多个条件的方法(&(条件1)(条件2))。 (6)searchCons.setCountLimit(limitsize)问题,有时查询时会报limitsize的异常,这是在遍历查询结果时出现的问题,下面是遍历的部分代码: while (namingEnum != null && namingEnum.hasMore()) 可以手工设置一个limitsize,当while循环次数到达limitsize时跳出while循环。 (7)注意关闭DirContext
3 遍历结果要注意的问题。 (1) 时间的处理
private String getConvertTime(Object time) { SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); if (time == null || "".equalsIgnoreCase(time.toString().trim())) { return ""; } String strTime = time.toString().trim(); if (strTime.indexOf(".") != -1) { strTime = strTime.substring(0, strTime.indexOf(".")); } long longTime = Long.valueOf(strTime); GregorianCalendar Win32Epoch = new GregorianCalendar(1601, Calendar.JANUARY, 1); Win32Epoch.setTimeZone(TimeZone.getTimeZone("China")); Date Win32EpochDate = Win32Epoch.getTime(); long TimeSinceWin32Epoch = longTime / 10000 + Win32EpochDate.getTime(); Date lastLogon = new Date(TimeSinceWin32Epoch); return sf.format(lastLogon); }
这个时间是基于格林威治1601年1月1日的,这要处理两个问题,a:加上1601年1月1日这个基础时间-Win32EpochDate.getTime(),b:格林威治时间与你所在时区有偏移量(Win32Epoch.setTimeZone(TimeZone.getTimeZone("China")); (2) lastLogon与lastLogonTimestamp,其中lastLogon至少在一台AD上是实时更新的,而lastLogonTimestamp则不是通常半个月才会更新,lastLogon因为存在在不同AD上的同步问题,所以需要在所有AD上都找到lastLogon,并找出最大值才是最后的登录时间。 (3)id类的处理,id属性值是一串二进制数据,需要进行转换字符串。
private static String getGUID(byte[] inArr) { StringBuffer guid = new StringBuffer(); for (int i = 0; i < inArr.length; i++) { StringBuffer dblByte = new StringBuffer(Integer.toHexString(inArr[i] & 0xff)); if (dblByte.length() == 1) { guid.append("0"); } guid.append(dblByte); } return guid.toString(); }
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-02-03
最后修改:2012-02-03
为什么我自定义的objectClass搜索不到呢,我在命令行用命令可以搜到条目,用LdapBrowser也可以看到条目结构和内容。但是在程序里面一直报异常。
我代码如下: 连接代码: public static DirContext getLDAPConnection() throws NamingException { String root = "relationName=relation,dc=example,dc=com"; String LDAPPassword = "secret"; Hashtable<String, String> env = new Hashtable<String, String>(); env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, "ldap://localhost:389"); env.put(Context.SECURITY_AUTHENTICATION, "simple"); env.put(Context.SECURITY_PRINCIPAL, root); env.put(Context.SECURITY_CREDENTIALS, LDAPPassword); DirContext ctx = new InitialDirContext(env); return ctx; } 搜索代码: public static NamingEnumeration<SearchResult> getLDAPResultList( DirContext ctx) { NamingEnumeration<SearchResult> enums = null; try { String filter = "(objectclass=*)"; SearchControls searchControls = new SearchControls(); searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); enums = ctx.search("", filter, searchControls); if (ctx != null) { ctx.close(); } return enums; } catch (javax.naming.AuthenticationException e) { e.printStackTrace(); return enums; } catch (Exception e) { e.printStackTrace(); return enums; } } 异常代码: javax.naming.NameNotFoundException: [LDAP: error code 32 - No Such Object]; remaining name '' |
|
返回顶楼 | |
浏览 3277 次