文档章节

ldap AD域 objectGUID objectSID

giianhui
 giianhui
发布于 2016/05/27 11:18
字数 1738
阅读 69
收藏 0
package org.jd.test;

import java.io.UnsupportedEncodingException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Hashtable;
import java.util.Vector;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
/**
 * 非ssl方式获取域的组织成员信息
 * @author ganjh
 *
 */
public class AdTest {
	
	/**
	 * 域:test.jd.com
	 * user:hhx
	 * password:12345678
	 * 域控服务器ip:10.0.6.151
	 * @param name
	 * @return
	 * @throws UnsupportedEncodingException 
	 */
	public String GetADInfo(String name) throws UnsupportedEncodingException {
		String userName = name; // 用户名称
		if (userName == null) {
			userName = "";
		}
		Object company = "";
		String host = "10.0.6.151"; // AD服务器
		String port = "389"; // 端口
		String url = new String("ldap://" + host + ":" + port);

		Hashtable HashEnv = new Hashtable();
		// String adminName ="CN=oyxiaoyuanxy,CN=Users,DC=Hebmc,DC=com";//AD的用户名
		String adminName = "test\\hhx"; // 注意用户名的写法:domain\User
		String adminPassword = "12345678"; // 密码
		HashEnv.put(Context.SECURITY_AUTHENTICATION, "simple"); // LDAP访问安全级别
		HashEnv.put(Context.SECURITY_PRINCIPAL, adminName); // AD User
		HashEnv.put(Context.SECURITY_CREDENTIALS, adminPassword); // AD Password
		HashEnv.put(Context.INITIAL_CONTEXT_FACTORY,
				"com.sun.jndi.ldap.LdapCtxFactory"); // LDAP工厂类
		HashEnv.put(Context.PROVIDER_URL, url);
		try {
			LdapContext ctx = new InitialLdapContext(HashEnv, null);
			// 域节点
			String searchBase = "OU=金地集团,DC=test,DC=jd,DC=com";
			// LDAP搜索过滤器类
			String searchFilter = "objectClass=User";
			// 搜索控制器
			SearchControls searchCtls = new SearchControls(); // Create the
			// search
			// controls
			// 创建搜索控制器
			searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE); // Specify

			// the
			// search
			// scope
			// 设置搜索范围
			// searchCtls.setSearchScope(SearchControls.OBJECT_SCOPE); //
			// Specify the search scope 设置搜索范围
			// String returnedAtts[] = { "memberOf", "distinguishedName",
			// "Pwd-Last-Set", "User-Password", "cn" };// 定制返回属性
			String returnedAtts[] = { "company","User-Password","cn","objectSID","objectGUID","description" };// 定制返回属性
			// String returnedAtts[] = { "url", "whenChanged", "employeeID",
			// "name", "userPrincipalName", "physicalDeliveryOfficeName",
			// "departmentNumber", "telephoneNumber", "homePhone",
			// "mobile", "department", "sAMAccountName", "whenChanged",
			// "mail" }; // 定制返回属性
			searchCtls.setReturningAttributes(returnedAtts); // 设置返回属性集
			// 根据设置的域节点、过滤器类和搜索控制器搜索LDAP得到结果
			NamingEnumeration answer = ctx.search(searchBase, searchFilter,
			searchCtls);// Search for objects using the filter
			// 初始化搜索结果数为0
			int totalResults = 0;// Specify the attributes to return
			int rows = 0;
			while (answer.hasMoreElements()) {// 遍历结果集
				SearchResult sr = (SearchResult) answer.next();// 得到符合搜索条件的DN
				System.out.println(++rows
				+ "************************************************");
				String dn = sr.getName();
				System.out.println(dn);
				String match = dn.split("CN=")[1].split(",")[0];// 返回格式一般是CN=ptyh,OU=专卖
				System.out.println(match);
//				if (userName.equals(match)) {
					Attributes Attrs = sr.getAttributes();// 得到符合条件的属性集
					if (Attrs != null) {
						try {
							for (NamingEnumeration ne = Attrs.getAll(); ne
									.hasMore();) {
								Attribute Attr = (Attribute) ne.next();// 得到下一个属性
								System.out.println(" AttributeID=属性名:"
										+ Attr.getID().toString());
								if("objectGUID".equals(Attr.getID())){
									String st = getGUID(Attr.get().toString().getBytes());
									// 读取属性值
									for (NamingEnumeration e = Attr.getAll(); e
											.hasMore(); totalResults++) {
//										Vector c = (Vector)e.next();
//										System.out.println(c.get(0));
										company = new String(e.next().toString().getBytes("GB2312"),"utf-8");
										System.out
												.println("    AttributeValues=属性值:"
														+ new String(company.toString().getBytes("GB2312"),"utf-8"));
									}
								}
								System.out.println("    ---------------");
							}
						} catch (NamingException e) {
							System.err.println("Throw Exception : " + e);
						}
//					}// if
				}
			}// while
			System.out
					.println("************************************************");
			System.out.println("Number: " + totalResults);
			ctx.close();
		} catch (NamingException e) {
			e.printStackTrace();
			System.err.println("Throw Exception : " + e);
		}
		return company.toString();
	}

	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();
	}

	public static void main(String args[]) throws Exception {
		// 实例化
		AdTest ad = new AdTest();
		String company = ad.GetADInfo("huanghx");
		
//		Class.forName("oracle.jdbc.driver.OracleDriver"); 
//		Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl","eas","kingdee"); 
//		String sql = "insert into ct_cos_test(fid,objectguid) values('11111','"+company+"')";
//		PreparedStatement ps = conn.prepareStatement(sql);
////		System.out.println(ps.executeUpdate());
//		
////		rs.close();
//		ps.close();
//		conn.close();
//	}

}


 

补充:

网上通过ldap操作AD的例子很多,我也是通过网络搜索然后成功的搜索了公司未知结构的AD,中间经历了一些波折,下面总结一下过程,我相信对需要操作AD的码工码农们多多少少是有些帮助。

1 获取DirContext要注意的地方。

以下是构造DirContext的基本代码:

Java代码
  1. DirContext ctx = null
  2. String ldapURL = "ldap://10.0.15.1:389"
  3. String user = "test@xxx.com"
  4. String password = "restart#123"
  5. Hashtable env = new Hashtable(); 
  6. env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 
  7. env.put(Context.SECURITY_AUTHENTICATION, "simple"); 
  8. env.put(Context.PROVIDER_URL, ldapURL); 
  9. env.put(Context.SECURITY_PRINCIPAL, user); 
  10. env.put(Context.SECURITY_CREDENTIALS, password); 
  11. ctx = new InitialDirContext(env);
DirContext ctx = null;
  String ldapURL = "ldap://10.0.15.1:389";
  String user = "test@xxx.com";
  String password = "restart#123";
  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结构未知,所以查询仍然要保守点。

Java代码
  1. DirContext cnt = null
  2.   try 
  3.   { 
  4.    cnt = this.getContext(); 
  5.    String base = "dc=xxx,dc=com"
  6.    String filter = "(&(objectClass=user)(sAMAccountName=*test*))"
  7.    int limitsize = 1
  8.    SearchControls searchCons = new SearchControls(); 
  9.    NamingEnumeration namingEnum = null
  10.    searchCons.setSearchScope(2); 
  11.    searchCons.setCountLimit(limitsize); 
  12.    searchCons.setTimeLimit(0); 
  13.    namingEnum = cnt.search(base, filter, searchCons); 
  14.    print(namingEnum, base, limitsize); 
  15.   } 
  16.   catch (Exception e) 
  17.   { 
  18.    e.printStackTrace(); 
  19.   } 
  20.   finally 
  21.   { 
  22.    if (cnt != null
  23.    { 
  24.     cnt.close(); 
  25.    } 
  26.   } 
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为登录帐号名。
(3)searchCons.setSearchScope(2),设为2会查询子节点。

(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) 时间的处理

Java代码
  1. private String getConvertTime(Object time) 
  2.   SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 
  3.   if (time == null || "".equalsIgnoreCase(time.toString().trim())) 
  4.   { 
  5.    return ""
  6.   } 
  7.   String strTime = time.toString().trim(); 
  8.  
  9.   if (strTime.indexOf(".") != -1
  10.   { 
  11.    strTime = strTime.substring(0, strTime.indexOf(".")); 
  12.   } 
  13.   long longTime = Long.valueOf(strTime); 
  14.  
  15.   GregorianCalendar Win32Epoch = new GregorianCalendar(1601, Calendar.JANUARY, 1); 
  16.   Win32Epoch.setTimeZone(TimeZone.getTimeZone("China")); 
  17.   Date Win32EpochDate = Win32Epoch.getTime(); 
  18.   long TimeSinceWin32Epoch = longTime / 10000 + Win32EpochDate.getTime();  
  19.   Date lastLogon = new Date(TimeSinceWin32Epoch); 
  20.   return sf.format(lastLogon); 
  21.  
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属性值是一串二进制数据,需要进行转换字符串。

  1. private static String getGUID(byte[] inArr) 
  2.   StringBuffer guid = new StringBuffer(); 
  3.   for (int i = 0; i < inArr.length; i++) 
  4.   { 
  5.    StringBuffer dblByte = new StringBuffer(Integer.toHexString(inArr[i] & 0xff)); 
  6.    if (dblByte.length() == 1
  7.    { 
  8.     guid.append("0"); 
  9.    } 
  10.    guid.append(dblByte); 
  11.   } 
  12.   return guid.toString(); 

本文转载自:http://blog.csdn.net/giianhui/article/details/8179688

giianhui
粉丝 6
博文 287
码字总数 0
作品 0
深圳
技术主管
私信 提问
ldap获取数据中的objectGUID乱码问题

声明: 1、解决办法是从一个英文网站找到的,现在找不到了,不是我自己解决的 2、连接ldap的方法,也是从网上拷贝,因为方法是固定和通用的 3、欢迎拍砖和开骂,真的,但是至少骂完后告诉我哪...

hlyton
2015/11/17
0
0
windows 2012新建额外域控没有netlogon和SYSVOL共享的解决办法

公司新建域控由于分公司需要辅助域控,就新建了一台额外域控,但是该域控建好后发现组策略不生效,检查sysvol文件夹一片空白,肯定是没有从主域控复制过来,使用dcdiag检查,有下面报错 目录...

wanghao20
2017/04/25
0
0
DNS故障求教,域环境下连不上DNS

域环境下,无法连接DNS.用dcdiag /c /v检查结果如下 目录服务器诊断 正在执行初始化设置: 正在尝试查找主服务器... * 正在验证本地计算机 WIN-9G5M179SOL4 是否为目录服务器。 主服务器 = WI...

余润平
2016/11/04
174
0
批量创建导入导出域用户

批量添加域用户 一、 AD用户帐户复制 1、在“AD域和计算机”中建一个作为样板的用户,如S1。 2、设置相关需要的选项,如所属的用户组、登录时间、用户下次登录时需更改密码等。 3、在S1上/右...

技术小甜
2017/11/16
0
0
Adprep命令在Server 2003显示无效命令的解决

有刚学AD的同行问,我怎么按书本运行adprep /forestprep,显示adprep.exe 命令不可用呢? 以下是一个小小的解答。 Active Directory Schema 是用来定义AD中的类别(classes)和属性(attribu...

像教授
2017/11/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

OpenStack 简介和几种安装方式总结

OpenStack :是一个由NASA和Rackspace合作研发并发起的,以Apache许可证授权的自由软件和开放源代码项目。项目目标是提供实施简单、可大规模扩展、丰富、标准统一的云计算管理平台。OpenSta...

小海bug
昨天
5
0
DDD(五)

1、引言 之前学习了解了DDD中实体这一概念,那么接下来需要了解的就是值对象、唯一标识。值对象,值就是数字1、2、3,字符串“1”,“2”,“3”,值时对象的特征,对象是一个事物的具体描述...

MrYuZixian
昨天
6
0
数据库中间件MyCat

什么是MyCat? 查看官网的介绍是这样说的 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务、ACID、可以替代MySQL的加强版数据库 一个可以视为MySQL集群的企业级数据库,用来替代昂贵...

沉浮_
昨天
6
0
解决Mac下VSCode打开zsh乱码

1.乱码问题 iTerm2终端使用Zsh,并且配置Zsh主题,该主题主题需要安装字体来支持箭头效果,在iTerm2中设置这个字体,但是VSCode里这个箭头还是显示乱码。 iTerm2展示如下: VSCode展示如下: 2...

HelloDeveloper
昨天
7
0
常用物流快递单号查询接口种类及对接方法

目前快递查询接口有两种方式可以对接,一是和顺丰、圆通、中通、天天、韵达、德邦这些快递公司一一对接接口,二是和快递鸟这样第三方集成接口一次性对接多家常用快递。第一种耗费时间长,但是...

程序的小猿
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部